I'm writing a new PyQt app. I'm trying to do everything related to the program and ui using as much of the PyQt APIs as possible as a means to improve my knowledge of PyQt and Qt in general.
The question I have is, is there an API within PyQt/Qt to handle command line argument parsing elegantly?
My research so far has turned up:
So how do PyQt applications normally handle this? or is opt_parser/argparse the way to go?
This is far from a nice solution...
#!/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)
Argument Parsing using sys. Your program will accept an arbitrary number of arguments passed from the command-line (or terminal) while getting executed. The program will print out the arguments that were passed and the total number of arguments. Notice that the first argument is always the name of the Python file.
To parse command line parameters, Commons CLI uses the DefaultParser implementation of the CommandlineParser interface. DefaultParser has a method called parse() which accepts the options object and the args from the command line. Finally, you can use the HelpFormatter to print the help information to the user.
After importing the library, argparse. ArgumentParser() initializes the parser so that you can start to add custom arguments. To add your arguments, use parser. add_argument() .
The best solution here is using the argparse
module's parse_known_args()
method (docs) to process the non-Qt command line options first. It's no more work in configuring the ArgumentParser
—it just changes which method you call, and gives you a tuple instead of a single object in the return. That gives you the best of both worlds.
A simplified example that catches only a couple of the Qt 4.8 arguments and a few others, but gives the general idea.
# 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.
Assume you were to run this like so:
$ python my_script.py -dograb --swallow=unladen 3 -style cde
Then parsed_args
would have the usual Namespace
with holy_hand_grenade
set to 3
and --swallow
set to 'unladen'
, while unparsed_args
would have a simple list: ['-dograb', '-style,' 'cde']
. This in turn can be passed normally to the QApplication
with the inclusion of the program name from sys.argv[0]
(thanks to marcin for pointing this out). We use sys.argv[:1]
to get an array for concatenation with unparsed_args
; you could just as well do [sys.argv[0]]
Among other things, this lets you set up your application to specify whether to launch the Qt UI, to run as a command line, to run unit tests, and so forth instead if you so desired. Handling the non-Qt (or anything else) arguments first is better because it does not leave argparse
dependent on the setup you're using, but the other way around.
Use argparse if you're using Python 2.7
(optparse if < 2.7
), the package doesn't have to be specific to PyQt for you to handle commandline options.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With