Search code examples
pythonargparse

'Clever' ways of switching between GUI and CLI modes with `Gooey`


I'm putting together a first attempt at a GUI program that wraps a really basic script (so that someone less CLI-savvy can run it).

One thing I had hoped, was that the script would still be CLI-able for those that are so inclined, with identical options.

I'm using Gooey for this as it seems nice and simple for someone getting started, but now I'm stuck about how to go about 'toggling' it.

In order to use the GUI, a python framework binary has to be used to execute the script, so my first thought was to look for someone calling the script explicitly with a non-framework binary, and having the shebang point at #!/usr/bin/env pythonw the rest of the time. I think this works in principle, but at the moment I can only think to use a simple if-else for the test.

This is fine, however, the @Gooey decorator requires the use of GooeyParser not ArgumentParser (from argparse). So at the moment, this would mean I need my whole argument ingesting function twice in the code, which feels decidedly non-pythonic.

e.g:

from gooey import Gooey, GooeyParser

@Gooey(program_name="Hi I'm progam X")
def gui_args():
    """Parse GUI arguments"""    
    parser = GooeyParser()
    parser.add_argument(
        "-f",
        "--file",
        action="store",
        widget="FileChooser",
        help="Some input file."
        )


from argparse import ArgumentParser
def get_args():
    """Parse command line arguments"""    
    parser = ArgumentParser()
    parser.add_argument(
        "-f",
        "--file",
        action="store",
        help="Some input file."
        )

def main():
     if <some_framework_python_test>:
          args = gui_args()
     else:
          args = get_args()

Is there a clever way I can switch between the GUI and CLI behavior without having to duplicate code, based on how the code is launched?

Other ideas I had include toggling the decorator based on some other threads, but its quite complex, and I would also need to switch GooeyParser to ArgumentParser in the actual code. Or perhaps Gooey already provides for this and I'm missing something obvious (I know for instance, Gooey handles argparse-style help formatting.

I don't know much about framework python either, so I don't know if what I'm proposing would work. Open to all suggestions! At the moment, running the code without specifying a pythonw binary just throws an error that Gooey can't find a screen.


Solution

  • So as I expected, there most certainly was a 'clever'/elegant way.

    There is a (currently) undocumented option --ignore-gooey which will make the script behave as a normal python script.

    An issue has been created on the github repo, and the author is going to document this in the not too distant future.

    Gooey actually spits this argument out in the terminal as a full representation of the command that was run, with all the arguments provided in the GUI, which was how I noticed it, when dispatching the actual code to be run.

    In the interests of a comprehensive answer, if you ordinarily called your GUI program like so*:

    $ pythonw MyGooeyScript.py
    

    to launch a full GUI session, you can instead call it like so:

    $ pythonw --ignore-gooey  MyGooeyScript.py <options>
    

    *It is sometimes necessary to launch python in unbuffered mode, with -u.