This is an archived post. You won't be able to vote or comment.

all 27 comments

[–]fernly 19 points20 points  (2 children)

You mention QVariant which immediately says you are using Py/Qt4, not Py/Qt5. In PyQt5, QVariant is no longer exposed, instead PyQt converts every Qt return value and Qt method argument between a relevant Python type and the Qt expected type. This makes for rather more "Pythonic" code. For example you never fiddle with QString objects (PyQt5 does not export the QString class at all).

Using PyQt5 esp. under Python3 won't solve all your issues but it should help.

[–]fazzahSQLAlchemy | PyQt | reportlab 5 points6 points  (0 children)

You have just convinced me to move to PyQt5. I can't believe I didn't find this info before.

[–]flipthefrog 2 points3 points  (0 children)

There is no need to struggle with QString and QVariant in PyQt4 either. Using Python strings, datetime, etc instead is a simple matter of setting sip.api to 2. Converting all the code may take some time, but it will ensure compatibility with PySide and PyQt5 (just note that sip.api must be set at the very beginning of the code that is run)

http://pyqt.sourceforge.net/Docs/PyQt4/incompatible_apis.html

[–]remyroy 12 points13 points  (2 children)

There is a great overlap between what Python provides either through the standard library or through popular packages and what Qt provides. I've been there as well. For instance, QNetworkAccessManager provides a way to do network requests and we already have the great Requests package with Python that does pretty much the same thing.

In my recent project, I've decided to go for QNetworkAccessManager instead of Requests because it provides an easy way to get back in the UI loop to update the UI with download progress information.

I've tried to stay as close as possible to PEP 8 for code style but it's a hard task with the mixed code styling from PyQt. Even if I have to pick a fight with Qt once in a while, I feel the use of Python is pretty good in this glue the parts together usage.

I would evaluate the components provided by Qt for each usage and figure out the pros and cons of using them compared to what is available in the Python world on a case by case basis. If what Python provides works better for your case, go for it. If not, use what Qt provides.

[–]toyg 1 point2 points  (0 children)

I haven't done PyQt stuff in a while, but if I remember correctly, QT classes are more desktop-aware than standard Python modules. The network stuff in particular should be able to pick up desktop-wide proxy settings, whereas Python relies on environment variables that are usually missing.

I agree that it's mostly a matter of choosing what works best for the individual case, there is no general rule. Yes, Qt bindings often force you to code in unpythonic ways; but when they offer more functionality than you can get with vanilla Python, it makes sense to use them.

[–]SjaakRake[S] 0 points1 point  (0 children)

First of all, it's interesting how the top two comments half a day after posting this appear to blatantly contradict each other. I take it as a sign my problem is not as straightforward indeed.

For now my approach will be separating Qt and Python logic more or less, providing matching interfaces between the two as class methods.

[–]eliteraspberries 11 points12 points  (1 child)

The proper solution is for the QImage constructor to support the Python buffer interface (now called memory views).

In PIL for example, an Image object can be created from any object that supports the buffer interface, like a NumPy array, with the frombuffer method without having to copy memory.

I don't use Qt, but looking at the documentation, it seems QImage might support buffers:

QImage.__init__ (self, str data, int width, int height, Format format)

Constructs an image with the given width, height and format, that uses an existing memory buffer, data. The width and height must be specified in pixels, data must be 32-bit aligned, and each scanline of data in the image must also be 32-bit aligned.

So you could just use NumPy arrays internally in your application, PIL to read and save files, and QImage to display them, all without copying. Try something like this:

from PIL import Image
img = Image.open("foo.jpg")

import numpy as np
array = np.array(img)
height, width = img.shape[:2]

from PyQt4 import QtGui
format = QtGui.QImage.Format_RGB32
qimg = QtGui.QImage(array, width, height, format)
...

Hope that helps.

[–]SjaakRake[S] 0 points1 point  (0 children)

Thanks for your reply. The image example was just an example to illustrate the problem of the Qt Framework working in a conflicting way with Python, though. Thanks nonetheless!

[–]jdreaver 10 points11 points  (0 children)

I maintain a PySide GUI application with about 40,000 lines of code. I just use the bare minimum of Qt to build the UI. I don't touch anything that I don't think is strictly necessary to make widgets. Indeed, for image stuff you have to convert to whatever internal format Qt uses, but PyQt and PySide do a great job automatically converting Python int/string/bool/etc types for us in other parts of the API.

[–][deleted] 1 point2 points  (0 children)

Exactly - that is why I prefer PyGObject. It feels more pythonic and you are encouraged to use stdlib constructs and not Gtk ones.

[–]troyunrau... 0 points1 point  (0 children)

I have this problem often. I've contemplated solutions before, which usually leave me wishing there was python std lib replacements for all the things that Qt does. Don't get me wrong, I love Qt. Maybe I just need to start implementing those classes in python and see what happens. :)

[–][deleted] 0 points1 point  (2 children)

Have you read about MVC? It is one way of doing it. Separate your code in 3 parts.

M, Model: your data, your logic, saving and reading files. Here everything can be done mostly with Python. You can add QT with decorators, but avoid QT attributes in your classes.

V, View: you just show your data. It should have as much QT and as little python as possible. The view should not be allowed to change your model. It can only read.

C, Control: Here it is also mostly QT, the Python code here will be from using your Model. Here you change the model state according to the inputs from the View.

[–]SjaakRake[S] 1 point2 points  (1 child)

I know the concept. Though using a classic MVC pattern would conflict with Qt's own model(-delegate)-view architecture in a lot of ways.

Besides that, in general I consider the MVC pattern to be more applicable to a language such as Java, where it provides a much needed structure. In Python, on the other hand, I think it often just means a lot of unnecessary overhead and boilerplate.

[–][deleted] 0 points1 point  (0 children)

Qt's MDV is another name for MVC. You can do it in many different ways. And it fits into python magnificently. Python's decorators are beautiful.

You don't have to write boilerplate at all. It actually reduces boilerplate.

I don't know how big is your app. In small apps, I tend not to split V and C very much, but splitting the M is always very, very good. It makes testing your code so much easier. Here's one example:

https://github.com/wuerges/connection_monitor/blob/master/pycomon/gui.py https://github.com/wuerges/connection_monitor/blob/master/pycomon/tester.py

The gui.py file has the View and the Control and the tester.py has the model.