kliment / Printrun

Pronterface, Pronsole, and Printcore - Pure Python 3d printing host software

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

wx._core.wxAssertionError: C++ assertion ""image.IsOk()"" failed when installed using pip

Poikilos opened this issue · comments

Searching online for this obscure-sounding error followed by "bitmap.cpp(593) in wxBitmap(): invalid image" in wx's C++ core didn't yield much except for other people confused by it, but on a closer look by a developer (me), it just means the image is missing. I'm stating the basics in case of other people finding this issue and getting confused by it. The issue is that the program is not looking in the right places for certain images, and I provide code below that solves it for cases where pronterface as installed via pip.

  • Version: 2.0.0rc8 (via pip)
  • OS: Devuan 4 (chimaera) (based on Debian 11 (bullseye))

Note about not using a virtualenv: Yeah, I know everyone says use a virtualenv but I have several programs installed like this (to avoid old bugs in programs due to Debian and Devuan policies regarding vetting packages for apt), and automating updates like cd Printrun && git pull && cd .. && python3 -m pip install --user --upgrade Printrun stores everything in .local and I can prevent pip from having to compile wx (and several other dependencies) multiple times (for each virtualenv that uses it) when the dependency updates.

Actual behavior

The imagefile function in utils.py instead only looks in:

  • candidate="/usr/share/pronterface/images"
  • local_candidate="$HOME/.local/bin/images" (this one seems wrong)
  • frozen_candidate="$HOME/.local/lib/python3.9/site-packages/printrun/images"
  • relative="$HOME/.local/bin/images"

Expected behavior

local_candidate seems like it should be "$HOME/.local/share/pronterface/images" instead of using the bin directory like relative already does, but if you really want to keep that for some reason (), that's fine (I use a separate share_candidate variable in the first added check below). This is confirmed to fix the error caused by the pip install then running pronterface.py from the path (from anywhere, using only the filename to run it). However, though the GUI now loads I still get the GUI error:
09:28:46 AM: can't open file 'pronterface.png' (error 2: No such file or directory)
09:28:46 AM: Failed to load image from file "pronterface.png".

Therefore, I also check in ./.local/share/pixmaps below.

In the imagefile function in utils.py, change

    local_candidate = os.path.join(os.path.dirname(sys.argv[0]),
                                   "images", filename)
    if os.path.exists(local_candidate):
        return local_candidate

to

    local_candidate = os.path.join(os.path.dirname(sys.argv[0]),
                                   "images", filename)
    if os.path.exists(local_candidate):
        return local_candidate
    # The code above isn't changed. Below is new:
    my_local_share = os.path.join(
        os.path.dirname(os.path.dirname(sys.argv[0])),
        "share",
        "pronterface"
    )
    share_candidate = os.path.join(my_local_share, "images", filename)
    if os.path.exists(share_candidate):
        return share_candidate

Or if you prefer, replace the entire function with something neater, using lookup_file:

def imagefile(filename):
    my_local_share = os.path.join(
        os.path.dirname(os.path.dirname(sys.argv[0])),
        "share",
        "pronterface"
    )
    image_dirs = [
        os.path.join(DATADIR, 'pronterface', 'images'),
        os.path.join(os.path.dirname(sys.argv[0]), "images"),
        os.path.join(my_local_share, "images"),
        os.path.join(
            getattr(sys, "_MEIPASS", os.path.dirname(os.path.abspath(__file__))),
            "images"
        ),  # frozen
    ]
    path = lookup_file(filename, image_dirs)
    if path == filename:
        # The file wasn't found in any known location, so use a relative
        #   path.
        path = os.path.join("images", filename)
    return path

Both are tested and working.

In either case, you must also make the following change in the pixmapfile function in utils.py:

Change

    shared_pixmaps_dir = os.path.join(DATADIR, 'pixmaps')
    return lookup_file(filename, [shared_pixmaps_dir])

to

    shared_pixmaps_dir = os.path.join(DATADIR, 'pixmaps')
    local_pixmaps_dir = os.path.join(
        os.path.dirname(os.path.dirname(sys.argv[0])),
        "share",
        "pixmaps"
    )
    pixmaps_dirs = [shared_pixmaps_dir, local_pixmaps_dir]    
    return lookup_file(filename, pixmaps_dirs)

These two additional checks are confirmed to fix the error (occurs in several places if fixed in the caller rather than using the comprehensive fix above) caused by the pip install then running pronterface.py from the path (from anywhere, using only the filename to run it): wx._core.wxAssertionError: C++ assertion ""image.IsOk()"" failed at /tmp/pip-install-0sdyo0e0/wxpython_e90d1c545c024e62b1f5e84d431bd0b3/ext/wxWidgets/src/gtk/bitmap.cpp(593) in wxBitmap(): invalid image

Let me know if I should submit a PR and which version of the change you prefer for imagefile.

Wow, thank you for your extensive research and documentation. It would be lovely to get it in PR form, and the lookup_file solution definitely seems more maintainable. The file lookup is definitely fragile and this has caused headaches for multiple packagers, so it's a welcome fix. Thank you!

Ok, here it is: #1285

  • Since you said others often bump into pathing issues, I added docstrings which may help diagnose things more quickly.