I will describe one possible way to achieve this using the following features:
We want to create a package layout that can support a CLI interface, an importable library, and a GUI all while sharing as much code as possible.
Although text and graphical interfaces are very different we can provide a consistent API with careful consideration. This way users can easily use our library or either interface without starting all over again.
First we will layout a single-file CLI script using argparse similar to the Unix wc tool that takes a text file and outputs the following information:
We'll discuss the __name__ == __main__ Python idiom, separating the argument parsing from the main function, and why keeping as little as possible in __main__ is better for reusability.
There are several pros and cons to providing others with a single-file script. It's easy to develop and simple to read, but it requires any user to have the correct version of Python installed. It's also difficult for other developers to reuse the code in their own projects or deploy to PyPI.
Next we'll take our single-file script and expand it into a basic Python package using a main folder, init.py, and a cli.py script to expose the same CLI as before.
We'll discuss how to restructure the main and parsing functions from step 1 into an public API defined by the init.py that exposes the same CLI functionality as a library.
We won't dive into setup.py at all, but there will be links and a brief description on the various tools to layout a package such as cookiecutter and setup.py.
The Gooey project can easily expose a CLI as GUI with a few decorators. We'll discuss briefly how to use Gooey and some of the extra functionality it provides to create more advanced GUIs.
We'll also give a simple mental model for how it maps argparse argument types to GUI widgets.
Until step 3 all we required of users was a working Python 3 installation. However, adding Gooey requires users to have a working Python installer, the Gooey library, and wxPython. Typically GUIs are meant for higher-level users so asking them to install all of this to benefit from our little app is too much.
Instead we'll see how we run PyInstaller on our entry script to package up all our dependencies including Python itself into a simple executable. We'll briefly discuss the build and dist output folders from PyInstaller along with the ability to use it to package all sorts of complicated Python applications using Qt, Numpy, etc.
End-users in management don't even have to know we used Python!