2015-03-11 18 views
7

Sto usando click (http://click.pocoo.org/3/) per creare un'applicazione a riga di comando, ma non so come creare una shell per questa applicazione.
Supponiamo che io sto scrivendo un programma chiamato prova e ho chiamato i comandi subtest1 e subtest2Creazione di un'applicazione della riga di comando shell con Python e Click

ero in grado di farlo funzionare da terminale come:

$ test subtest1 
$ test subtest2 

Ma quello che Stavo pensando è una shell, quindi potrei fare:

$ test 
>> subtest1 
>> subtest2 

È questa poss ible con clic?

+1

Forse si può mettere insieme qualcosa usando il [ 'funzione di prompt'] (http: // click .pocoo.org/3/istruzioni /). – mkrieger1

risposta

11

Questo non è impossibile con il clic, ma non c'è nemmeno un supporto integrato per questo. Il primo che dovresti fare è rendere invocabile la richiamata di gruppo senza un sottocomando passando invoke_without_command=True nel decoratore di gruppo (come descritto here). Quindi la callback del tuo gruppo dovrebbe implementare un REPL. Python ha il framework cmd per farlo nella libreria standard. La creazione dei sottocomandi dei clic disponibili implica la sostituzione di cmd.Cmd.default, come nel frammento di codice seguente. Ottenere tutti i dettagli a destra, come help, dovrebbe essere fattibile in poche righe.

import click 
import cmd 

class REPL(cmd.Cmd): 
    def __init__(self, ctx): 
     cmd.Cmd.__init__(self) 
     self.ctx = ctx 

    def default(self, line): 
     subcommand = cli.commands.get(line) 
     if subcommand: 
      self.ctx.invoke(subcommand) 
     else: 
      return cmd.Cmd.default(self, line) 

@click.group(invoke_without_command=True) 
@click.pass_context 
def cli(ctx): 
    if ctx.invoked_subcommand is None: 
     repl = REPL(ctx) 
     repl.cmdloop() 

@cli.command() 
def a(): 
    """The `a` command prints an 'a'.""" 
    print "a" 

@cli.command() 
def b(): 
    """The `b` command prints a 'b'.""" 
    print "b" 

if __name__ == "__main__": 
    cli() 
+1

Come farei per passare argomenti aggiuntivi al sottocomando e farli analizzare da Click? –

+0

So che sono abbastanza in ritardo per questo gioco, ma controlla la mia risposta per come potresti gestire argomenti addizionali ai sottocomandi. (È basato su questa risposta, in nessun modo sarei arrivato fino a qui senza di esso). – vimalloc

1

Stavo cercando di fare qualcosa di simile all'OP, ma con opzioni aggiuntive/sotto-sotto-comandi nidificati. La prima risposta con il modulo cmd incorporato non ha funzionato nel mio caso; forse con un po 'di più giocherellando .. Ma ho appena incontrato click-shell. Non ho avuto la possibilità di testarlo estensivamente, ma finora sembra funzionare esattamente come previsto.

0

So che questo è super vecchio, ma ho lavorato anche alla soluzione di fpbhb per supportare le opzioni. Sono sicuro che questo potrebbe usare un po 'più di lavoro, ma qui è un esempio di base di come potrebbe essere fatto:

import click 
import cmd 
import sys 

from click import BaseCommand, UsageError 


class REPL(cmd.Cmd): 
    def __init__(self, ctx): 
     cmd.Cmd.__init__(self) 
     self.ctx = ctx 

    def default(self, line): 
     subcommand = line.split()[0] 
     args = line.split()[1:] 

     subcommand = cli.commands.get(subcommand) 
     if subcommand: 
      try: 
       subcommand.parse_args(self.ctx, args) 
       self.ctx.forward(subcommand) 
      except UsageError as e: 
       print(e.format_message()) 
     else: 
      return cmd.Cmd.default(self, line) 


@click.group(invoke_without_command=True) 
@click.pass_context 
def cli(ctx): 
    if ctx.invoked_subcommand is None: 
     repl = REPL(ctx) 
     repl.cmdloop() 


@cli.command() 
@click.option('--foo', required=True) 
def a(foo): 
    print("a") 
    print(foo) 
    return 'banana' 


@cli.command() 
@click.option('--foo', required=True) 
def b(foo): 
    print("b") 
    print(foo) 

if __name__ == "__main__": 
    cli()