2012-07-29 14 views
8

Escribo una nueva aplicación PyQt. Intento hacer todo lo relacionado con el programa y utilizar todas las API de PyQt como sea posible para mejorar mi conocimiento de PyQt y Qt en general.Análisis de argumento de línea de comando elegante para PyQt

La pregunta que tengo es, ¿hay una API dentro de PyQt/Qt para manejar el análisis de línea de comandos de manera elegante?

Mi investigación hasta ahora ha aparecido:

  • un ejemplo de cómo hacer que play nice with python's opt_parser módulo, excepto que no se ocupa de QApplication construida en el análisis arg.
  • PyKDE's KCmdLineArgs (que presenta una dependencia no deseada KDE)
  • parece que KCmdLineArgs está siendo portado aguas arriba de Qt5.1 como QCommandLineParser, lo cual es genial, pero me gustaría ser capaz de utilizarlo ahora, no 18 meses desde ahora.

Entonces, ¿cómo las aplicaciones PyQt normalmente manejan esto? o es opt_parser/argparse el camino a seguir?

Esto está lejos de ser una buena solución ...

#!/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

El objetivo de mi publicación en lateral.netmanagers.com.ar que ha mencionado es que maneja el análisis de línea de comandos integrado de QApplication. Usted define sus propios argumentos usando opt_parse/argparse/whatever, y siempre que no defina los mismos que utiliza QApplication, todo solo funciona. –

Respuesta

3

Uso argparse si está usando Python 2.7 (optparse si < 2.7), el paquete no tiene que ser específico para PyQt para que usted pueda manejar las opciones de línea de comandos.

+2

+1 ya que no hay ninguna razón para necesitar instalaciones provistas por pyqt cuando python stdlib tiene un módulo con todas las funciones. – jdi

+2

Bien, leí en argparse y parece agradable, sin embargo, no resuelve los problemas de jugar bien con QApplication integrado en el análisis arg. Por ejemplo: si ejecuta 'myPyQyApp.py -style cde' desde la línea de comando, QApplication intercepta ese argumento y hace que todo se vea como 1996, pero argparse no tiene idea de que esto está sucediendo. Por eso estoy buscando una solución PyQt. Si no existe ninguno, entonces que así sea, pero la solución stdlib no es óptima. –

+2

Si no desea que Qt analice la línea de comando, simplemente cree la aplicación de la siguiente manera: 'app = QtGui.QApplication ([])' – pwuertz

5

La mejor solución aquí es usar el método argparse del módulo parse_known_args() (docs) para procesar primero las opciones de línea de comando que no sean Qt. Ya no es necesario configurar el ArgumentParser; solo cambia el método al que llama y le proporciona una tupla en lugar de un único objeto en la declaración. Eso te da lo mejor de ambos mundos.

Un ejemplo simplificado que capta solo un par de los argumentos de Qt 4.8 y algunos otros, pero da la idea general.

# 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. 

Supongamos que se va a ejecutar este modo:

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

Entonces parsed_args tendría la costumbre Namespace con holy_hand_grenade conjunto de 3 y --swallow conjunto de 'unladen', mientras unparsed_args tendría una lista simple: ['-dograb', '-style,' 'cde'] . Esto a su vez se puede pasar normalmente al QApplication con la inclusión del nombre del programa de sys.argv[0] (gracias a marcin para pointing this out). Usamos sys.argv[:1] para obtener una matriz para la concatenación con unparsed_args; también podría hacer [sys.argv[0]]

Entre otras cosas, esto le permite configurar su aplicación para especificar si desea iniciar la interfaz de usuario de Qt, ejecutarla como línea de comando, ejecutar pruebas unitarias, etc. si lo hace deseado. Primero, es mejor manejar los argumentos que no son Qt (o cualquier otra cosa) porque no deja argparse dependiendo de la configuración que esté utilizando, sino al revés.

+0

¿Qué sucede si quiero permitir que la aplicación qt tenga acceso a los argumentos analizados? – qed

+0

@qed, en ese caso, podría simplemente pasar 'sys.argv' directamente en lugar de' unparsed_args'. –

+0

¿Pero puedo usar argparse dentro de QApplication? – qed

0

Realmente deberías probar docopt. No necesita ninguna definición de argumento.Tiene cadena de "Uso:" y argumentos no analizados como entrada, los pasa a la función docopt(), y tiene argumentos analizados como salida.

Cuestiones relacionadas