Michael Herrmann

Python and Qt: 3,000 hours of developer insight

Published Thursday November 15th, 2018
32 Comments on Python and Qt: 3,000 hours of developer insight
Posted in Dev Loop, Qt for Python, Uncategorized | Tags: , , , ,

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

Do you like this? Share it
Share on LinkedInGoogle+Share on FacebookTweet about this on Twitter

Posted in Dev Loop, Qt for Python, Uncategorized | Tags: , , , ,

32 comments

Jason says:

I still don’t get why people use Python when there is QML (cough*JavaScript*cough)?

I think maybe it’s due to the JS side of Qt lacking some things (File IO?) I know it’s frowned upon byt Qt folk that you can write an entire app in QML, but I don’t think that’s their decision to make. Why should you need to know C++/Qt, Python and JavaScript? I would like you (or anyone else) to only need to know one.

Michael Michael says:

Python has much better libraries for doing desktop-related tasks. JavaScript is a web-first language. I know there’s (eg.) Node. But Python’s target has been desktop for 28 years, whereas it’s rather new for JS.

By the way, did I mention I don’t like JS? 😉

adrian says:

Unfortunaly, I cannot Access network shares in Windows, so it becomes useless for me.

Rusty says:

How about using Rust and QT?

Andy Brice says:

You can create your app on a later version of Mac than you taget. E.g. I build PerfectTablePlan on macOS 10.13 for macOS 10.10 … 10.14 .

Michael Michael says:

That does not reflect my experience – fman would not start for some users on 10.11 when I built on 10.13: https://fman.io/blog/battling-with-macos/

Sacha says:

I Wonder how difficult was to make the dark flat design.
From my experience with Qt, I never success to make a nice flat interface without the help of a designer.
So, I aways keep the default gray style which may looks old.

Michael Michael says:

See the sections “Built-in styles” and “Custom colors” in my article https://build-system.fman.io/pyqt5-tutorial for a starting point to making a dark design with Qt 🙂

Mike says:

Maybe fman does something differently but generally you use -mmacosx-version-min flag to define the lowest macos version where your app can be run. See https://clang.llvm.org/docs/CommandGuide/clang.html

Mike says:

Sorry I guess I clicked the wrong reply button. Was meant to be a reply for the comment above.

Michael Michael says:

It could also well be that I did something wrong and you can, if you are careful, deploy to 10.11 from 10.13. For me, it was easiest to simply build on 10.10. Then I don’t have to “worry” about backwards-compatibility.

Erik says:

Interesting, we use the Qt Installer framework for deploying, updating the stack.
The installer simply sets up a scheduled task to check for updates and install them.

Fabrice Salvaire says:

As a Python/Qt promoter I would say that Python is great but we must take care to the GIL issue which is hard to circumvent. And startup time can also be an issue and require tuning, a lot of lazy loading etc.

Else users will be disappointed.

Anon says:

fman is balls because it is not free software

Michael Michael says:

😀 Thank you for a productive comment.

no says:

anon is right.

Greg says:

Just came across this article today via reddit. Thanks for taking the time to document everything about this build. I am a new Python programmer and just finally about to start working on my first standalone program. I am glad to have found your guides, and I will definitely be checking fman out as well!

Michael Michael says:

Thanks! I’m happy to hear you found it useful 🙂

d3fault says:

Hi will you please provide a concrete example demonstrating how Python is more productive than C++? The blog post announcing the new Python support [0] used a silly “star destroyer” vs. “millenium falcon” analogy but provided no example, and your blog post provides no example either. The “Hello Qt Python” blog post [1] does show some Python code, but it looks like roughly the same amount of code as C++ (but you’ve lost: compile time safety, access to the ever growing list of static analysis sanity checks provided by clang-tidy/CppCoreGuidelines, and the ability to #include other C/C++ libs without wasting your time creating bindings. so what have you gained?)

Feel free to link me to some other site explaining how Python is more productive than C++, so you don’t have to repeat the arguments here. I’m curious because if Python really is more productive than C++, then maybe I’ll switch. But as it stands, repeatedly spouting “Python is more productive than C++” is just spreading FUD (Fear, Uncertainty, and Doubt) against C++.

[0] — http://blog.qt.io/blog/2018/04/13/qt-for-python-is-coming-to-a-computer-near-you/
[1] — http://blog.qt.io/blog/2018/05/04/hello-qt-for-python/

Michael Michael says:

I could now spend much time giving plenty of examples, but it sounds like your mind is pretty much set in stone. Already “Hello World” is 1 line in Python and 5+ in C++. If you’re happy with C++, do stay with it. But if you want to expand your horizon, just write a few little programs in both languages. Eg. parsing a JSON file. You will feel the difference.

d3fault says:

Where’s this 1-line “hello world” you speak of? The code on the “Hello Qt Python” is 35 lines, which is about the same as C++. I said I’d be willing to switch if you could show me an example of Pyhon being more productive. Please stop spreading FUD of you can’t/won’t back up your claim.

Also: Python was the first language I ever tried to learn… but imo C++ blows it out of the water in every aspect. Yes a lot of people use Python, but that doesn’t automatically make it good.

Michael Michael says:

print(‘hello world’)

is the Python Hello World example I had in mind. One line. C++:

#include
using namespace std;
int main()
{
cout << "Hello, World!";
return 0;
}

d3fault says:

thought we were talking Qt here… but thanks for at least providing an example :-/

Keith Kyzivat says:

Here’s a Qt for Python Hello World application in 3 lines:

from PySide2.QtWidgets import *
QApplication()
QMessageBox.about(None, “Hello World”, “Hello World”)

d3fault says:

Here’s a Qt for C++ (cling) Hello World application in 3 lines:

#include
QApplication a;
QMessageBox::about(0, “Hello World”, “Hello World”);

Same amount of lines as Python, but by using Python you’ve LOST:
-linting / access to the ever growing list of static analysis sanity checks provided by clang-tidy/CppCoreGuidelines/clazy
-the ability to #include other C/C++ libs without wasting your time creating bindings
-runtime performance
-strict typing
-multiline lambdas
-true multithreading (due to the global interpreter lock)
-scoping rules that aren’t dependent on white space

So what have you GAINED by using Python?
-the ability to import other Python libs without wasting your time creating bindings
……and that’s all.

George Bellarious says:

“d3fault”, you phase your questions and points like Mr Herrmann owes you something, when he has gone ahead and provided this article to you for free.

Rather than lean on one person to prove to you that Python is more productive than C++, I recommend you do some wider-ranging Google searching, or better, implement a project in it (trying to learn it once a while ago doesn’t count).

Danny says:

Interesting project and nicely presented.

It’s a shame however that you don’t have comments on your site because you make several assertions and assumptions that I flat out don’t agree with.

For one thing, if my workflow requires copying, moving or otherwise, I wouldn’t use a GUI app; I’d use the command line.

I also completely disagree that python is a more productive environment than C++. Yes the lack of a compilation cycle is nice but you lose runtime performance, strict typing and linting that catch many silly mistakes at build time. Python also lacks basic features like multiline lambdas, true multithreading (due to the global interpreter lock) and scoping rules that aren’t dependant on white space.

It seems like you’re trying to solve a problem that was already solved years ago.

Michael Michael says:

You’re free to stay with C++ if you feel more productive with it. I know I am not.

d3fault says:

Mike, we’re definitely on the same side of the argument (<3), but I want to point out that even C++ can be used in an interactive/interpreted environment, as demonstrated here: http://blog.qt.io/blog/2018/06/15/scripting-in-c/

Öme says:

Great article. We cross-platform developers are all facing with same issues.

Mahadev says:

It is a Python interface for Qt, one of the most powerful, and popular cross-platform GUI library. PyQt is a blend of Python .
https://crbtech.in/programmes/java-training-programme

Robert says:

Great tool. Look forward to using it.

Commenting closed.

Get started today with Qt Download now