[PyQt] PyQt4 and Python 3.0

Daniel Miller daniel at keystonewood.com
Tue Oct 7 16:10:57 BST 2008


I should clarify a few things before I embark on a rebuttal:

- I have deployed my code to my end users many times since I started  
to build my PyQt4 compatibility layer (it is not finished yet, and I  
can't afford to stop pushing out bug fixes and new features for a few  
months while I do a rewrite).

- I am moving to PyQt4 because I need to use some of the new features  
(the Graphics View Framework, for one). If I did not need these new  
features in PyQt4 I'd be content to stay with PyQt3.


On Oct 6, 2008, at 2:32 PM, Phil Thompson wrote:
> On Mon, 6 Oct 2008 12:27:42 -0400, Daniel Miller  
> <daniel at keystonewood.com>
> wrote:
>>>
>>>> I hope Phil can stick to the really needed stuff. Porting stuff  
>>>> from
>>>> Qt/KDE 3 to 4 has proven to be draining work which I hope to avoid
>>>> having to do again in the near future.
>>>
>>> Which is why I say don't port, rewrite.
>
> Before I start I should point out that I say "rewrite", not  
> "rewrite from
> scratch". My main point is that, when presented with a major change in
> technology then don't try to get away with making as few changes as
> possible - which is what "port" means to me.

Why should I rewrite an entire code base that is working fine and  
does not need to be touched? That kind of disruption only introduces  
new bugs. It seems with your logic that whenever I need even one new  
feature from PyQt4 I am forced to rewrite my entire application (or  
at least everything that touches PyQt). It's insane to think that  
everyone who uses PyQt has the time and resources to do that.

>> If you don't believe me go read Joel Spolsky's article
>> "Things You Should Never Do, Part I" <http://www.joelonsoftware.com/
>> articles/fog0000000069.html>
>
> ...everybody knows that, in real life, software *does* rust.

I think you're being stubborn... Of course software ages, but if it  
(or at least most parts of it) meets the requirements then I should  
not be forced to rewrite it.

>> For one thing, when an investor gives the OK to spend many hours to
>> rewrite an application s/he normally expects to see new features and
>> or functionality, none of which will exist when the only new feature
>> is a new version of a library.
>
> They expect to see whatever you've agreed to provide. If they see
> insufficient benefit in moving to a new library, then don't do it.

Again, I don't think you're being entirely honest here. I need to add  
new features, which are required by my employer. To add those new  
features, I need the latest version of PyQt. However, I don't want  
(nor can I afford) to rewrite my application every time I decide to  
upgrade to a new version of PyQt. I'm starting to see this as a  
significant disadvantage to using PyQt in the first place--the devs  
are not concerned with maintaining backward compatibility or making  
the upgrade path smooth for existing users. It seems to be a library  
for toy projects that can be torn down and implemented from scratch  
on a whim.

>> I'm in the process of maintaining and
>> porting an application from PyQt3 to PyQt4. ...
>
> So you spend a lot of time refactoring the code so that when you do  
> the
> fork it is as late as possible and the amount of code being forked  
> is a
> little as possible.

It's not a fork because there are never two separate branches of code  
that need to be maintained at the same time. There just comes a point  
in time when the application no longer uses PyQt3 and at that point  
it uses PyQt4--this is analogous to switching to a new version of any  
module or package.

>> Unfortunately, the PyQt team doesn't ship the Q3Support classes,
>
> It is available.

Actually, I'm using the parts of it that I can, although it's a royal  
pain because PyQt needs to be patched, and sometimes the patch needs  
to be updated by hand since it's not always up to date with the  
latest version of PyQt4. Not to mention, I still need to write a  
compatibility layer because the names of all the support classes  
start with Q3. The compatibility layer consists of 'qt' and 'qttable'  
modules that contain classes that look and act exactly like they did  
in PyQt3.

>
>> which are critical for anyone who can't simply throw everything away
>> and start over new. The Python 3 team, in contrast to the PyQt team,
>> is making the switch from Python2 to Python3 as painless as possible.
>> The py2to3 tool should minimize the porting pain, and they have very
>> well-though-out advice for those who need to support both Python2 and
>> Python3: develop for 2.6 and use py2to3 to "compile" a Python3
>> version. IMPORTANT: DO NOT TOUCH the py2to3 generated code until
>> you're ready to throw away (forever) the old 2.6 code base. I.E. if
>> you need to make changes, make them in the 2.6 version of the code
>> and "recompile" with py2to3 for as long as both versions of Python
>> must be supported.
>
> If the Python approach requires you to specifically target 2.6 then  
> move to
> 3.0 then I think that approach is flawed as it involves two  
> transitions. I
> would recommend treating 2.6 as an incremental upgrade from 2.5 and  
> do a
> single transition from 2.x to 3.0.

It is certainly not flawed if you need a version of your code that  
works on both Python 2 and Python 3. Or if you want to do two small  
transitions in a controlled manner with a few minor code changes  
rather than one big transition that results in a major rewrite and  
possibly lots of downtime. If there is no single version of PyQt that  
runs on both versions then the major rewrite will be the only option.  
That means that every application that uses PyQt will be doing  
another major rewrite when they switch to Python 3 and  
PyQtX...hopefully they will all be done with the migration to PyQt4  
by then...

>
>> ...
>> The new version is exactly like the old one except it uses PyQt4
>> instead of PyQt3; no learning curve, no new file formats, nothing
>> different except PyQt4.
>
> That's the problem. You then end up with a design that's based on  
> the needs
> of PyQt3 and trying to bend PyQt4 to fit it. You also find that  
> it's more
> difficult than it should be to exploit new features of PyQt4.

Not at all. You talk about PyQt4 like it's some entirely new beast  
sharing next to nothing with the old PyQt3. Maybe that's how the  
underlying implementation looks, but the end-user functionality is  
95% the same as it was in PyQt3--it still shows windows with widgets  
on the screen, and users still interact with them in the same way  
they did before. Adapting PyQt4 to the old PyQt3 API is not that  
hard, it's just very tedious.

However, it's much less tedious to implement a single new version of  
qt.QSettings based on PyQt4.QtGui.QSettings than to rewrite every  
place in my application that happens to touch the QSettings API (for  
example). Newer parts of may application can import  
PyQt.QtGui.QSettings and use that API if they need the new  
functionality. Incidentally, there's not much new in QSettings, so I  
don't really see why there was a need to change the API so  
drastically in a backward-incompatible way--it just causes a lot of  
pain. If the API really needed to be changed, then the old methods  
should have been deprecated in a transitional version, giving time to  
migrate to the new API's without completely breaking backward  
compatibility. Then new releases could be pushed out while the  
migration was taking place rather than requiring a rewrite through  
the duration of which no releases can be made because critical things  
are still broken.

> If all you end up with is the same application, doing the same  
> thing but
> using PyQt4 instead of PyQt3, then I don't understand why you  
> bothered.

I need new features in PyQt4...if I didn't I certainly wouldn't have  
switched.

But I want to change (and debug) one thing at a time. I don't want to  
be debugging PyQt migration bugs at the same time I'm debugging new  
features in my code. That's why I want a seamless transition. When I  
switch from PyQt3 to PyQt4 I want that to be the only change that I'm  
making--then I'll know where the problem originated. If I'm  
introducing PyQt4 at the same time I'm introducing new features I'll  
have no idea if the problem is related to my implementation of the  
new feature or if it's a bug in PyQt4.

> I would reverse it. Write a compatibility layer that makes PyQt3  
> look like
> PyQt4. Then, when you finally throw away PyQt3, you throw away the
> compatibility layer as well.

Umm, that would be fine if my application was coded against the PyQt4  
API, but then I wouldn't need to have this discussion, would I? The  
point is to be able to release updates while I'm working on the  
transition to PyQt4, without maintaining two completely independent  
code branches.

> Note that I wouldn't call the Q3Support classes a compatibility layer.

I agree. In a C++ app it might be possible (even simple?) to do  
global find/replace and use the compile step to make sure you've  
renamed everything properly, but with Python this is not so simple.  
It would have been nice if PyQt4 would have provided a 'qt' module  
(namespace) that had the exact same contents as PyQt3--that's what  
I'm writing for my application. I can migrate away from using this  
layer as I refactor and develop new features in my application. The  
key is that it's done incrementally in a stable and predictable  
manner, and it's done on my timeframe, and I can release as often as  
I need to during the transition.

>> While it is unquestionably worthwhile for me to write a compatibility
>> layer for my project, if several teams out there decide to port their
>> projects this way then the combined cost of each team developing
>> their own compatibility layer far exceeds the cost of doing it once
>> for everyone.
>
> There's nothing stopping you organising this, or publishing your
> compatibility layer.

Unfortunately my compatibility layer probably would not be very  
useful to the general public since I'm only implementing what is  
absolutely necessary for my application.

> Perhaps if I gave a fuller definition of "rewrite"...
>
> "To refactor your application over a period of time so that the  
> code is
> exactly the same as it would have been if you had been able to  
> start with a
> blank piece of paper."

Why should I start with a blank piece of paper when I already have  
99% of what I need and it's all working correctly? You seem to think  
there's value in rewriting code that is working perfectly. I see this  
as a waste of my valuable time, which I could be spending  
implementing new features.

> Note that you will not achieve this [starting with a blank piece of  
> paper] with the way you are doing your
> compatibility layer.

Nor do I want to achieve that. I want to move forward; I do not want  
to spend lots of time rewriting code that already works.

> To me a much more important element of the process than all these  
> layers is
> automated, comprehensive testing (the holy grail of GUI  
> development). With
> that in place you can refactor with real confidence without needing to
> fork.

And with that in place switching to PyQt4 would be just as painful.  
Introducing something as wildly different as PyQt4 would break so  
many tests that there would be no way to tell if you're getting  
anything done as you start to try to fix the damage.

fix 1... run tests... 4023 tests failed
fix 2... run tests... 4022 tests failed
fix 3... run tests... 4056 tests failed
...

The point of testing is to make small changes and fix one thing at a  
time. When something breaks you know exactly what it is because  
you've got a test telling you what it is, and when you fix it you  
know it's fixed because all your tests pass again. However, this  
development strategy will not work in a migration to PyQt4 because so  
many tests will break initially that you'd have no idea where to  
start--the number of broken tests would be huge, and any given fix  
may or may not reduce the number of failing tests. In fact, the  
number of broken tests could quite plausibly increase if you happen  
to fix one thing but at the same time break something else. The  
problem is that there is no way to introduce PyQt4 gradually.

The damage is done in PyQt4, and we can't turn back the clock  
(although a good compatibility layer could still be written). Just  
don't introduce this type of major breakage again, please. Especially  
not in the transition to Python 3, as it would require us to test two  
new things at the same time: Python 3 and PyQtX.

~ Daniel



More information about the PyQt mailing list