Python and Qt: 3,000 hours of developer insight

With Qt for Python released, it's time to look at the powerful capabilities of these two technologies. This article details one solopreneur's experiences.

The task

Back in 2016, I started developing a cross-platform file manager called fman. Its goal: To let you work with files more efficiently than Explorer on Windows or Finder on Mac. If you know Total Commander and Sublime Text, a combination of the two is what I am going for. Here's what it looks like:

fman screenshot

Picking technologies for a desktop app

The biggest question, in the beginning, was which GUI framework to use. fman's choice needs to tick the following boxes:

  • Cross-platform (Windows, Mac, Linux)
  • Good performance
  • Support for custom styles
  • Fast development

At the time, Electron was the most-hyped project. It has a lot of advantages: You can use proven web technologies. It runs on all platforms. Customizing the UI of your application is trivial by means of CSS. Overall, it's a very powerful technology.

The big problem with Electron is performance. In particular, the startup time was too high for a file manager: On an admittedly old machine from 2010, simply launching Electron took five seconds.

I admit that my personal distaste for JavaScript also made it easier to discount Electron. Before I go off on a rant, let me give you just one detail that I find symptomatic: Do you know how JavaScript sorts numbers? Alphabetically. 'nuff said.

After considering a few technologies, I settled on Qt. It's cross-platform, has great performance and supports custom styles. What's more, you can use it from Python. This makes at least me orders of magnitude more productive than the default C++.

Writing a GUI with Python and Qt

Controlling Qt from Python is very easy. You simply install Python and use its package manager to fetch the Qt bindings. Gone are the days where you had to set up gigabytes of software, or even Qt. It literally takes two minutes. I wrote a Python Qt tutorial that shows the exact steps and sample code if you're interested.

You can choose between two libraries for using Qt from Python:

  • PyQt is mature but requires you to purchase a license for commercial projects.
  • Qt for Python is a recent push by Qt the company to officially support Python. It's offered under the LGPL and can thus often be used for free.

From a code perspective, it makes no difference because the APIs are virtually identical. fman uses PyQt because it is more mature. But given that Qt for Python is now officially supported, I hope to switch to it eventually.

Deploying to multiple platforms

Once you've written an application with Python and Qt, you want to bring it into the hands of your users. This turns out to be surprisingly hard.

It starts with packaging. That is, turning your source code into a standalone executable. Special Python libraries exist for solving this task. But they never "just work". You may have to manually add DLLs that are only required on some Windows versions. Or avoid shipping shared libraries that are incompatible with those already present on the users' systems. Or add special handling for one of your dependencies. Etc.

Then come installers. On Windows, most users expect a file such as AppSetup.exe. On Mac, it's usually App.dmg. Whereas on Linux, the most common file formats are .deb.rpm and .pkg.tar.xz. Each of these technologies takes days to learn and set up. In total, I have spent weeks just creating fman installers for the various platforms.

Code signing

By default, operating systems show a warning when a user downloads and runs your app:

To prevent this, you need to code sign your application. This creates an electronic signature that lets the OS verify that the app really comes from you and has not been tampered with. Code signing requires a certificate, which acts like a private encryption key.

Obtaining a certificate differs across platforms. It's easiest on Linux, where everyone can generate their own (GPG) key. On Mac, you purchase a Developer Certificate from Apple. Windows is the most bureaucratic: Certificate vendors need to verify your identity, your address etc. The cheapest and easiest way I found was to obtain a Comodo certificate through a reseller, then have them certify my business – not me as an individual.

Once you have a certificate, code signing involves a few more subtleties: On Windows and Ubuntu, you want to ensure that SHA256 is used for maximum compatibility. On Linux, unattended builds can be tricky because of the need to inject the passphrase for the GPG key. Overall, however, it's doable.

Automatic updates

Like many modern applications, fman updates itself automatically. This enables a very rapid development cycle: I can release multiple new versions per day and get immediate feedback. Bugs are fixable in less than an hour. All users receive the fix immediately, so I don't get support requests for outdated problems.

While automatic updates are a blessing, they have also been very expensive to set up. The tasks we have encountered so far – packaging, installers and code signing – took a month or two. Automatic updates alone required the same investment again.

The most difficult platform for automatic updates was Windows. fman uses a Google technology called Omaha, which is for instance used to update Chrome. I wrote a tutorial that explains how it works.

Automatic updates on Mac were much easier thanks to the Sparkle update framework. The main challenge was to interface with it via Objective-C from Python. Here too I wrote an article that shows you how to do it.

Linux was "cleanest" for automatic updates. This is because modern distributions all have a built-in package manager such as apt or pacman. The steps for enabling automatic updates were typically:

  • Host a "repository" for the respective package manager. This is just a collection of static files such as .deb installers and metafiles that describe them.
  • Upload the installer to the repository, regenerating the metafiles.
  • Create a "repository file": It imports the repo into the user's package manager.

Because fman supports four Linux distributions, this still required learning quite a few tools. But once you've done it for two package managers, the others are pretty similar.

OS Versions

There aren't just different operating systems, there are also different versions of each OS. To support them, you must package your application on the earliest version. For instance, if you want your app to run on macOS 10.10+, then you need to build it on 10.10, not 10.14. Virtual machines are very useful for this. I show fman's setup in a video.

fman's build system

So how does fman cope with all this complexity? The answer is simple: A Python-based build script. It does everything from creating standalone executables to uploading to an update server. I feel strongly that releasing a desktop app should not take months, so am making it available as open source. Check it out if you are interested!

Conclusion

Python and Qt are great for writing desktop apps: Qt gives you speed, cross-platform support and stylability while Python makes you more productive. On the other hand, deployment is hard: Packaging, code signing, installers, and automatic updates require months of work. A new open source library called fbs aims to bring this down to minutes.

If you liked this post, you may also be interested in a webinar Michael is giving on the above topics. Sign up or watch it here: Americas / EMEA


Blog Topics:

Comments