Friday, August 8, 2014

Worry about Lion?

Today's code review was utilities.py, a whole collection of things related to QFile/QTextStream that kind of grew like a fungus while I was coding mainwindow and dealing with opening books. All I did to it was to clarify some commentary and add one minor feature to my "MemoryStream" class. Then I went to run its test driver.

When I'm coding, I usually use my macbook. But for this review phase, I wanted to take advantage of the larger screen on my desktop system. All the files are in dropbox and accessible from both systems. And both systems are set up with Qt/PyQt 5.3, and Wing IDE. So usually it is just a matter of which screen I feel like sitting at. Obviously I can't tote the big machine to the coffee shop, or curl up with it on a lawn chair in the back yard. But other than location, it doesn't usually matter which I use.

Usually. Today I ran the driver for utilities, and when it came to exercising ask_existing_file(), things got interesting.

def ask_existing_file(caption, parent=None, starting_path='', filter_string=''):
    # Ask the user to select a file
    (chosen_path, _) = QFileDialog.getOpenFileName(
            parent,
            caption,
            starting_path, filter_string
        )
    if len(chosen_path) == 0 : # user pressed Cancel
        return None
    return path_to_stream(chosen_path)

It's just a wrapper on getOpenFileName, covering up the awkward API that returns both a path and a filter string, and when a path is chosen, converts it into a QTextStream. Very straightforward and no place where my code could mess up the OS. Right?

So the test driver first calls it with the caption "Press CANCEL", and looks for a return of None. Then it calls it with a caption "Choose unreadable.txt" and I am supposed to use the file dialog to navigate to a file with 000 permissions, which will be detected as unreadable (in path_to_stream) and again return None. Finally the driver calls it with a caption directing me to choose a certain test input file that exists, and it will check that it got a text stream. Very plain-vanilla.

Except it crashed Python. The first, or sometimes the second, or definitely the third entry into getOpenFileName would result in a segfault at location 0000000000000120x, as the crash report helpfully noted the 64-bit address. Most of the time. Sometimes it would die with a "pure virtual method called" abort. But either way, it would segfault deep in the OS X Finder, called from getOpenFileName.

I was not fazed. I knew what to do. I just opened my laptop and ran the identical test, which worked perfectly, no crashes.

The difference? My desktop machine is an old Mac Pro with a 32-bit BIOS that cannot be upgraded past OS X "Lion" (10.7). While the laptop is proudly 10.9.4 "Mavericks". Other than that, the software environment is the same: same Python (3.3) and Qt/PyQt 5.3.

OK, so it looks as if anyone who runs PPQT on Lion is going to be disappointed to say the least, because it will segfault the first time they try to open a file. Should I worry? I think not. I will have to specify it is for Mavericks and up. Too bad about those with an old system that can't upgrade.

I would have a later desktop system but I am determined that my next desktop will have a 4K monitor. And Apple is inexplicably dragging their feet on producing a 4K iMac (which I'd buy in a heartbeat) or a 4K Thunderbolt display, to which I could dock my macbook.

No comments: