Repository navigation
test_grab_x11 failure when no X session is running #9577
Copy link
Copy link
Closed
Labels
Description
Activity
Here is the full trace:
=================================== FAILURES =================================== _________________________ TestImageGrab.test_grab_x11 __________________________ bbox = None, include_layered_windows = False, all_screens = False xdisplay = None, window = None def grab( bbox: tuple[int, int, int, int] | None = None, include_layered_windows: bool = False, all_screens: bool = False, xdisplay: str | None = None, window: int | ImageWin.HWND | None = None, ) -> Image.Image: im: Image.Image if xdisplay is None: if sys.platform == "darwin": fh, filepath = tempfile.mkstemp(".png") os.close(fh) args = ["screencapture"] if window is not None: args += ["-l", str(window)] elif bbox: left, top, right, bottom = bbox args += ["-R", f"{left},{top},{right-left},{bottom-top}"] args += ["-x", filepath] retcode = subprocess.call(args) if retcode: raise subprocess.CalledProcessError(retcode, args) im = Image.open(filepath) im.load() os.unlink(filepath) if bbox: if window is not None: # Determine if the window was in Retina mode or not # by capturing it without the shadow, # and checking how different the width is fh, filepath = tempfile.mkstemp(".png") os.close(fh) args = ["screencapture", "-l", str(window), "-o", "-x", filepath] retcode = subprocess.call(args) if retcode: raise subprocess.CalledProcessError(retcode, args) with Image.open(filepath) as im_no_shadow: retina = im.width - im_no_shadow.width > 100 os.unlink(filepath) # Since screencapture's -R does not work with -l, # crop the image manually if retina: left, top, right, bottom = bbox im_cropped = im.resize( (right - left, bottom - top), box=tuple(coord * 2 for coord in bbox), ) else: im_cropped = im.crop(bbox) im.close() return im_cropped else: im_resized = im.resize((right - left, bottom - top)) im.close() return im_resized return im elif sys.platform == "win32": if window is not None: all_screens = -1 offset, size, data = Image.core.grabscreen_win32( include_layered_windows, all_screens, int(window) if window is not None else 0, ) im = Image.frombytes( "RGB", size, data, # RGB, 32-bit line padding, origin lower left corner "raw", "BGR", (size[0] * 3 + 3) & -4, -1, ) if bbox: x0, y0 = offset left, top, right, bottom = bbox im = im.crop((left - x0, top - y0, right - x0, bottom - y0)) return im # Cast to Optional[str] needed for Windows and macOS. display_name: str | None = xdisplay try: if not Image.core.HAVE_XCB: msg = "Pillow was built without XCB support" raise OSError(msg) > size, data = Image.core.grabscreen_x11(display_name) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ E OSError: X connection failed: error 5 ../build/prototype/i386/usr/lib/python3.13/vendor-packages/PIL/ImageGrab.py:119: OSError During handling of the above exception, another exception occurred: self = <Tests.test_imagegrab.TestImageGrab object at 0x7fe48d8c6e90> @skip_unless_feature("xcb") def test_grab_x11(self) -> None: try: if sys.platform not in ("win32", "darwin"): > ImageGrab.grab() Tests/test_imagegrab.py:35: _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ bbox = None, include_layered_windows = False, all_screens = False xdisplay = None, window = None def grab( bbox: tuple[int, int, int, int] | None = None, include_layered_windows: bool = False, all_screens: bool = False, xdisplay: str | None = None, window: int | ImageWin.HWND | None = None, ) -> Image.Image: im: Image.Image if xdisplay is None: if sys.platform == "darwin": fh, filepath = tempfile.mkstemp(".png") os.close(fh) args = ["screencapture"] if window is not None: args += ["-l", str(window)] elif bbox: left, top, right, bottom = bbox args += ["-R", f"{left},{top},{right-left},{bottom-top}"] args += ["-x", filepath] retcode = subprocess.call(args) if retcode: raise subprocess.CalledProcessError(retcode, args) im = Image.open(filepath) im.load() os.unlink(filepath) if bbox: if window is not None: # Determine if the window was in Retina mode or not # by capturing it without the shadow, # and checking how different the width is fh, filepath = tempfile.mkstemp(".png") os.close(fh) args = ["screencapture", "-l", str(window), "-o", "-x", filepath] retcode = subprocess.call(args) if retcode: raise subprocess.CalledProcessError(retcode, args) with Image.open(filepath) as im_no_shadow: retina = im.width - im_no_shadow.width > 100 os.unlink(filepath) # Since screencapture's -R does not work with -l, # crop the image manually if retina: left, top, right, bottom = bbox im_cropped = im.resize( (right - left, bottom - top), box=tuple(coord * 2 for coord in bbox), ) else: im_cropped = im.crop(bbox) im.close() return im_cropped else: im_resized = im.resize((right - left, bottom - top)) im.close() return im_resized return im elif sys.platform == "win32": if window is not None: all_screens = -1 offset, size, data = Image.core.grabscreen_win32( include_layered_windows, all_screens, int(window) if window is not None else 0, ) im = Image.frombytes( "RGB", size, data, # RGB, 32-bit line padding, origin lower left corner "raw", "BGR", (size[0] * 3 + 3) & -4, -1, ) if bbox: x0, y0 = offset left, top, right, bottom = bbox im = im.crop((left - x0, top - y0, right - x0, bottom - y0)) return im # Cast to Optional[str] needed for Windows and macOS. display_name: str | None = xdisplay try: if not Image.core.HAVE_XCB: msg = "Pillow was built without XCB support" raise OSError(msg) size, data = Image.core.grabscreen_x11(display_name) except OSError: if display_name is None and sys.platform not in ("darwin", "win32"): if shutil.which("gnome-screenshot"): args = ["gnome-screenshot", "-f"] elif shutil.which("grim"): args = ["grim"] elif shutil.which("spectacle"): args = ["spectacle", "-n", "-b", "-f", "-o"] else: raise fh, filepath = tempfile.mkstemp(".png") os.close(fh) args.append(filepath) retcode = subprocess.call(args) if retcode: > raise subprocess.CalledProcessError(retcode, args) E subprocess.CalledProcessError: Command '['gnome-screenshot', '-f', '/tmp/tmpjeopzhzn.png']' returned non-zero exit status 1. ../build/prototype/i386/usr/lib/python3.13/vendor-packages/PIL/ImageGrab.py:135: CalledProcessError ----------------------------- Captured stderr call ----------------------------- (gnome-screenshot:15211): Gtk-WARNING **: 16:25:32.468: cannot open display: =========================== short test summary info ============================ SKIPPED [1] Tests/test_imagegrab.py:16: requires Windows or macOS SKIPPED [1] Tests/test_imagegrab.py:41: tests missing XCB SKIPPED [1] Tests/test_imagegrab.py:63: Only runs on macOS CI SKIPPED [1] Tests/test_imagegrab.py:87: macOS and Windows only SKIPPED [1] Tests/test_imagegrab.py:127: Windows only SKIPPED [1] Tests/test_imagegrab.py:139: Windows only SKIPPED [3] Tests/test_imagegrab.py:155: Linux with wl-clipboard only SKIPPED [2] Tests/test_imagegrab.py:171: Linux with wl-clipboard only FAILED Tests/test_imagegrab.py::TestImageGrab::test_grab_x11 - subprocess.Cal... =================== 1 failed, 2 passed, 11 skipped in 3.00s ==================== gmake: *** [/builds/jkulik/pillow-12.2.0/make-rules/python-common.mk:151: /builds/pillow/build/amd64-3.13/.tested] Error 1We're catching the 'X connection failed'
OSError, and then falling back to trying gnome-screenshot instead. #9321 started raisingsubprocess.CalledProcessErrorwhengnome-screenshotfails. So from one perspective, the real problem is thatgnome-screenshotisn't working.I've created #9578 to catch the error.
Thanks! With #9578, the test suite is green again and reports:
SKIPPED [1] Tests/test_imagegrab.py:39: Command '['gnome-screenshot', '-f', '/tmp/tmp2zm4fuy7.png']' returned non-zero exit status 1.
What did you do?
I ran the pillow 12.2.0 test suite on a machine where XCB (X protocol) support is available, but without a running X session.
What did you expect to happen?
All tests should pass.
What actually happened?
test_grab_x11failed with:What are your OS, Python and Pillow versions?