Python detect x server error when showing image

Viewed 760

Is there any way of catching an X server exception in Python when using Image.show()?

When I try to show an image over an ssh connection when I haven't used the -X or -Y option, I want to stop running the program, since this will be running in a loop so there's no point in trying to load more images.
This displays the error display.im6: unable to open X server ' @ error/display.c/DisplayImageCommand/428.'
But it doesn't seem possible to catch this since I think the OS is showing this error after the PIL Image.show() call is performed.

from PIL import Image
img = Image.open(img_name)
try:
    img.show()
except Exception as e:
    print(e)
    sys.exit()

The call never goes into the except call.

1 Answers

As can be seen from PIL's code at https://pillow.readthedocs.io/en/5.3.x/_modules/PIL/ImageShow.html , the show method in images will ultimately call os.system with a heuristically determined command to display the image. The problem, as can be seen here, is, that the return value of the os.system call is ignored, so, even when the image is not displayed, the program will never know that.

You could try monkey-patching os.system to raise an error if the original os.system returns anything other than zero, and then you'd have an exception. However, upon attempting it this way, I noticed that for my default viewer, it returns "0" as exit code anyway, even with a broken display, so it is not detectable with "system". You'd have to monkeypatch os.system with a function that would make a proper subprocess.Popen call and check not only the exit-code, but also the sdterr of the called command - it's starting to get tricky.

So, a second, simpler, and possibly safer route, is to have your program check the contents of the DISPLAY environment variable. If it is empty or invalid, any attempt to use the X display will fail:

import os

if not os.environ.get("DISPLAY"):
    raise RuntimeError("Display is not properly set. Aborting!")

Why is it that way? Historically PIL's (the original PIL, not the currently maintained Pillow) show code was a simple, hardcoded call to xv - it was probably found to be only useful for debugging purposes by the original library owners. Although today it is more sophisticated, looking for a suitable external viewer among a couple of (still hardcoded) options, is not a "first class UI" in any way. I think it is proper for your described use-case, but for anything beyond that, maybe the first option would be to move to matplotlib to display the images in a UI which is better controlled from the Python code, without having to resort to write full GUI code with Qt or Tkinter.

Related