2012-07-29 14 views
8

Sto scrivendo una nuova app PyQt. Sto provando a fare tutto ciò che riguarda il programma e ui usare il maggior numero possibile di API PyQt come mezzo per migliorare la mia conoscenza di PyQt e Qt in generale.Argomento da riga di comando elegante per PyQt

La domanda che ho è, esiste un'API in PyQt/Qt per gestire l'argomento della riga di comando che analizza elegantemente?

La mia ricerca finora è alzato:

  • un esempio di come farlo play nice with python's opt_parser modulo, tranne che non gestisce di QApplication costruito in arg analisi.
  • PyKDE's KCmdLineArgs (che introduce una dipendenza indesiderata KDE)
  • sembra KCmdLineArgs viene portato a monte per Qt5.1 come QCommandLineParser, che è fresco, ma mi piacerebbe essere in grado di usarlo ora, non 18 mesi da adesso.

Quindi, come le applicazioni PyQt gestiscono normalmente questo? o è opt_parser/argparse la strada da percorrere?

Questo è lontano da una bella soluzione ...

#!/usr/bin/python 
# -*- coding: utf-8 -*- 

import sys, argparse 
from PyQt4 import QtGui 

def main(argv): 

    app = QtGui.QApplication(argv) # QApplication eats argv in constructor 

    # We can get a QStringList out of QApplication of those arguments it 
    # didn't decide were reserved by Qt. 
    argv2 = app.arguments() 

    # now we need to turn them back into something that optparse/argparse 
    # can understand, since a QStringList is not what it wants 
    argv3 = [] 
    for i in argv2: 
    argv3.append(str(i)) 

    # now we can pass this to optparse/argparse 
    process_args(argv3) 

    # dummy app 
    mw = QtGui.QMainWindow() 
    mw.show() 
    sys.exit(app.exec_()) 

def process_args(argv): 
    parser = argparse.ArgumentParser(description='PyQt4 argstest', 
            add_help=False) 

    # we now have to add all of the options described at 
    # http://qt-project.org/doc/qt-4.8/qapplication.html#QApplication 
    # but have them do nothing - in order to have them show up in the help list 

    # add this to the list if Qt is a debug build (How to detect this?) 
    parser.add_argument("-nograb", action=ignore, 
         help="don't grab keyboard/mouse for debugging") 

    # add these to the list if Qt is a debug build for X11 
    parser.add_argument("-dograb", action=ignore, 
         help="grab keyboard/mouse for debugging") 
    parser.add_argument("-sync", action=ignore, 
         help="run in synchronous mode for debugging") 

    # add all the standard args that Qt will grab on all platforms 
    parser.add_argument("-reverse", action=ignore, 
         help="run program in Right-to-Left mode") 
    # an example -- there are 10 such items in the docs for QApplication 

    # then we need to figure out if we're running on X11 and add these 
    parser.add_argument("-name", action=ignore, 
         help="sets the application name") 
    # an example -- there are 13 such items in the docs 

    # reimplement help (which we disabled above) so that -help works rather 
    # than --help; done to be consistent with the style of args Qt wants 
    parser.add_argument("-h", "-help", action='help', 
         help="show this help message and exit") 

    parser.parse_args(argv[1:]) 

class ignore(argparse.Action): 
    # we create an action that does nothing, so the Qt args do nothing 
    def __call__(self, parser, namespace, values, option_string=None): 
    pass 

if __name__ == "__main__": 
    main(sys.argv) 
+2

L'intero punto del mio post su lateral.netmanagers.com.ar che hai menzionato è che gestisce l'analisi della riga di comando incorporata di QApplication. Si definiscono i propri argomenti usando opt_parse/argparse/qualunque e fintanto che non si definiscono gli stessi utilizzati da QApplication, tutto funziona correttamente. –

risposta

3

Usa argparse se si sta utilizzando Python 2.7 (optparse se < 2.7), il pacchetto non deve essere specifico per PyQt per voi gestire le opzioni della riga di comando.

+2

+1 in quanto non vi è motivo di aver bisogno di servizi forniti da pyqt quando python stdlib ha un modulo perfettamente funzionante. – jdi

+2

Ok, ho letto su argparse e sembra carino, ma non risolve il problema di giocare con l'analisi di argo di QApplication. Ad esempio: se esegui 'myPyQyApp.py-style cde' dalla riga di comando, QApplication intercetta quell'argomento e rende tutto simile al 1996, ma argparse non ha idea che stia accadendo. Ecco perché sto cercando una soluzione PyQt. Se non esiste, allora così sia, ma la soluzione stdlib non è ottimale. –

+2

Se non vuoi che Qt analizzi la riga di comando, crea l'applicazione in questo modo: 'app = QtGui.QApplication ([])' – pwuertz

5

La soluzione migliore qui è utilizzare il metodo parse_known_args() del modulo per elaborare prima le opzioni della riga di comando non Qt. Non c'è più lavoro nella configurazione di ArgumentParser -it cambia solo il metodo che chiami e ti dà una tupla invece di un singolo oggetto nel ritorno. Questo ti dà il meglio di entrambi i mondi.

Un esempio semplificato che cattura solo un paio degli argomenti di Qt 4.8 e pochi altri, ma dà l'idea generale.

# my_script.py 

import argparse 
from PyQt4 import QtGui # this will work with PySide.QtGui, too 

def process_cl_args(): 
    parser = argparse.ArgumentParser() 
    parser.add_argument('-s', '--swallow', action='store') # optional flag 
    parser.add_argument('holy_hand_grenade', action='store') # positional argument 

    parsed_args, unparsed_args = parser.parse_known_args() 
    return parsed_args, unparsed_args 

if __name__ == '__main__': 
    parsed_args, unparsed_args = process_cl_args() 
    # QApplication expects the first argument to be the program name. 
    qt_args = sys.argv[:1] + unparsed_args 
    app = QtGui.QApplication(qt_args) 
    # ... the rest of your handling: `sys.exit(app.exec_())`, etc. 

supponga si dovesse eseguire questo modo:

$ python my_script.py -dograb --swallow=unladen 3 -style cde 

Poi parsed_args avrebbe la solita Namespace con holy_hand_grenade set per 3 e --swallow insieme a 'unladen', mentre unparsed_args avrebbe un elenco semplice: ['-dograb', '-style,' 'cde'] . Questo a sua volta può essere passato normalmente allo QApplication con l'inclusione del nome del programma da sys.argv[0] (grazie a marcin per pointing this out). Usiamo sys.argv[:1] per ottenere una matrice per la concatenazione con unparsed_args; si potrebbe altrettanto bene fare [sys.argv[0]]

Tra le altre cose, questo consente di impostare la vostra applicazione per specificare se lanciare il Qt interfaccia utente, per l'esecuzione come una riga di comando, per eseguire unit test, e così via, invece se lo desiderato. Gestire prima gli argomenti non-Qt (o qualsiasi altra cosa) è meglio perché non lascia il argparse dipendente dal setup che si sta utilizzando, ma viceversa.

+0

Cosa succede se voglio consentire all'app qt di accedere agli argomenti analizzati? – qed

+0

@qed, in tal caso, potresti semplicemente passare 'sys.argv' direttamente invece di' unparsed_args'. –

+0

Ma posso usare argparse all'interno di QApplication? – qed

0

Si dovrebbe davvero provare docopt. Non ha bisogno di definizioni di argomenti.Hai come argomento "Usage:" string e unparars come argomento, passali nella funzione docopt() e hai analizzato gli argomenti come output.

Problemi correlati