Friday, April 17, 2015

The Py2.7 experiment

So I created a virtual environment with Python 2.7, and in it installed Qt and Sip and PyQt, and brought in a little test program to bundle. Pointless and ugly little thing but it runs and makes an app and a dialog box.

from __future__ import print_function
from __future__ import unicode_literals
from future_builtins import *

from PyQt5.QtWidgets import (
 QDialog,
 QMainWindow,
 QPlainTextEdit,
 QVBoxLayout,
 QHBoxLayout,
 QPushButton
 )
from PyQt5.QtWidgets import QApplication
import sys
args = []
if sys.platform == 'linux' :
 args = ['','-style','Cleanlooks']
app = QApplication(args)
mw = QMainWindow()
mw.show()
dlg = QDialog(mw)
hb = QHBoxLayout()
okb = QPushButton("OK")
okb.setDefault(True)
okb.clicked.connect(dlg.accept)
cab = QPushButton("Cancel")
cab.setDefault(False)
cab.clicked.connect(dlg.reject)
hb.addWidget(cab)
hb.addStretch()
hb.addWidget(okb)
vb = QVBoxLayout()
pte = QPlainTextEdit()
vb.addWidget(pte,1)
vb.addLayout(hb,0)
dlg.setLayout(vb)
print(dlg.exec_())
print(pte.document().toPlainText())

So this runs under Python 2.7. So I installed PyInstaller and bundled it. This failed because of an issue with the PyInstaller "hook" for PyQt5.Qt, which stupidly insists on including every module of Qt including Qml, which I did not install. But I had already fixed that in my copy of PyInstaller for Python3, and I knew just which file to edit, and did, and the resulting bundle now ran.

Then I ran the same job with the option to make a mac .app bundle and that worked too, even giving it the right icon. So, looking good.

I also installed py2app and tried it but first I hit an obvious programming error. It was an easily-diagnosed misspelling of the name of a class method that I had not run into before because it is in code specific to running in a virtual environment, and this was the first time I'd done that with py2app. After I fixed that (and opened a second issue on Oussoren's bitbucket page), it ran and made a bundle, but said bundle died immediately with an abort trap 6. No idea why, although I did notice that the qt.conf file py2app had left in the app Resources folder contained a path that could not possibly be correct. So I opened a third issue on the py2app site, but after I did that I mentally washed my hands of py2app. As Kevin O'Leary says on Shark Tank, "you are dead to me."

So how hard would it be to convert a Python3 app to Python2? I made a copy of my Cobro program and did the job. There were three issues. First, it used the Python3 urllib. Which is the Python2 urllib2 package. So I had to change two import statements and several statements that used urllib. The changes were only syntactic; just different names for the same operations.

And I had to change every call to super() to include the parent class name; again, only syntactic. Finally, running it from the command line it crashed trying to write the QSettings file. There is a bytes value which I passed to QByteArray, and for some reason Python seemed to think it needed to convert that to a string first, which didn't work, no surprise. All I had to do was wrap the expression in bytes().

Unfortunately the program crashed after it had cleared the settings, which meant that when it next came up, my long and carefully-curated list of webcomics that I read every day—was gone! No prob, I thought, I'll just restore from Time Machine. Nope! Because apparently years ago when first setting up Time Machine I had excluded ~/Library from the list of folders to back up. So later I will have to reconstruct my list of web comics.

The good news is that PyInstaller bundled cobro, although the resulting .app does not run; it dies looking for QWebEngineProcess, the undocumented piece of QWebEngine that has to exist but they don't tell you that, or where to put it. So not an error in PyInstaller, it's just that nobody has contributed a "hook" for QWebEngine. If I can figure out where it's supposed to be...

Never mind. What next? Do I really want to fork PPQT2 and make a Python2 version of it? It looks as if I'd get something that I could bundle. But it would be a chancy thing. I'm worried about having bugs like that string-handling thing in Cobro. To be really sure I ought to perform the same experiment in Ubuntu but you know, why? I'm quite confident it would work; PyInstaller was working with Python2 for PPQT version 1, in Ubuntu and Windows. I will ponder this over the weekend.

No comments: