Fix for pyqtdeploy-build bug on windows when folder and module have same name

Patrick Stinson patrickkidd at gmail.com
Wed Oct 14 17:29:58 BST 2020


Turns out PyErr_Print() (i.e. in pyqtdeploy_start.cpp) doesn’t print anything to console for windows. This means you don’t get any python exceptions from the app, which is a problem. Perhaps this is because I am using the release build from the pyqtdeploy-built sysroot. This led to the long debugging process described in my previous email, then once I had fixed that problem moving on to other exceptions in my app (e.g. Qt/PyQt not having ssl support). I think python exceptions should be printed by default, especially since this can be time consuming for a pyqtdeploy exe.

The following workaround gets the current python exception traceback as a QString. You would then replace PyErr_Print(); in pyqtdeploy_start.cpp:handle_expcetion() with "qDebug().noquote() << q_getTraceback();


QString q_getTraceback()
{
#define TRACEBACK_FETCH_ERROR(what) {errMsg = what; goto done;}

    // acquire global interpreter lock to ensure we are in a consistent state
    PyGILState_STATE gstate;
    gstate = PyGILState_Ensure();

    QString errMsg;
    QString result;

    PyObject* modStringIO = NULL;
    PyObject* modTB = NULL;
    PyObject* obStringIO = NULL;
    PyObject* obResult = NULL;

    PyObject* type, * value, * traceback;

    PyErr_Fetch(&type, &value, &traceback);
    PyErr_NormalizeException(&type, &value, &traceback);

    modStringIO = PyImport_ImportModule("io");
    if (modStringIO == NULL)
        TRACEBACK_FETCH_ERROR("can't import cStringIO");

    obStringIO = PyObject_CallMethod(modStringIO, (char*)"StringIO", NULL);

    /* Construct a cStringIO object */
    if (obStringIO == NULL)
        TRACEBACK_FETCH_ERROR("cStringIO.StringIO() failed");

    modTB = PyImport_ImportModule("traceback");
    if (modTB == NULL)
        TRACEBACK_FETCH_ERROR("can't import traceback");

    obResult = PyObject_CallMethod(modTB, (char*)"print_exception",
        (char*)"OOOOO",
        type, value ? value : Py_None,
        traceback ? traceback : Py_None,
        Py_None,
        obStringIO);

    if (obResult == NULL)
        TRACEBACK_FETCH_ERROR("traceback.print_exception() failed");
    Py_DECREF(obResult);

    obResult = PyObject_CallMethod(obStringIO, (char*)"getvalue", NULL);
    if (obResult == NULL)
        TRACEBACK_FETCH_ERROR("getvalue() failed.");

    /* And it should be a string all ready to go - duplicate it. */
    //if (!PyString_Check(obResult))
    //    TRACEBACK_FETCH_ERROR("getvalue() did not return a string");

    result = PyUnicode_AsUTF8(obResult);

done:

    // All finished - first see if we encountered an error
    if (result.isEmpty() && !errMsg.isEmpty())
    {
        result = errMsg;
    }

    Py_XDECREF(modStringIO);
    Py_XDECREF(modTB);
    Py_XDECREF(obStringIO);
    Py_XDECREF(obResult);
    Py_XDECREF(value);
    Py_XDECREF(traceback);
    Py_XDECREF(type);

    // we are done calling python API, release global interpreter lock
    PyGILState_Release(gstate);

    return result;
}


================

        // PyErr_Print();

        QString tb = q_getTraceback();
        printf(tb.toLatin1().constData());
        qDebug().noquote() << tb;


> On Oct 13, 2020, at 11:58 PM, Patrick Stinson <patrickkidd at gmail.com> wrote:
> 
> My windows build was exiting silently with error code one. There was no error printed on this one either at the C++ level in pyqtdeploy_main or in pyqtdeploy.builder.builder so I ended up having to debug both layers for a while to figure it out. Eventually I figured out that pdytools_module.cpp:find_module couldn’t find my module “pkdiagram.debug”.
> 
> Turns out the module was never added to the project.
> 
> Turns out pyqtdpeloy.builder.builder silently ignores a python app module added to the pyqtdeploy project if a folder exists with the same filename. In my case I had a debug.py in my app module and also had a “debug” folder in the app module folder.
> 
> I added this poorly chosen exception to builder.builder to point it out. I do think it should fail if the file isn’t found since it was explicitly added in the project:
> 
> diff --git a/builder/builder.py b/builder/builder.py
> index 62ee74a..b50e59b 100644
> --- a/builder/builder.py
> +++ b/builder/builder.py
> @@ -536,6 +536,8 @@ int main(int argc, char **argv)
>             # simple directory.
>             if os.path.isfile(src_path):
>                 to_freeze.append((src_path, dst_name))
> +            else:
> +                raise RuntimeError("Skipping freezing module: %s, because file not found: %s" % (name, src_path))
> 
>         elif isinstance(part, PythonPackage):
>             root = os.path.join(part_root_dir, src_name)
> 
> I imagine some error reporting could go a long way at both the C++ and python levels.
> 
> Cheers,
> -Patrick



More information about the PyQt mailing list