Package: src:pyautogui
Version: 0.0~git20230607111623.b4255d0-4
Severity: important
Tags: ftbfs patch
Dear maintainer:
During a rebuild of all packages in unstable, your package failed to build:
--------------------------------------------------------------------------------
[...]
debian/rules build
dh build --with python3 --buildsystem=pybuild
dh_update_autotools_config -O--buildsystem=pybuild
dh_autoreconf -O--buildsystem=pybuild
dh_auto_configure -O--buildsystem=pybuild
I: pybuild base:311: python3.12 setup.py config
/usr/lib/python3/dist-packages/setuptools/_distutils/dist.py:261: UserWarning:
Unknown distribution option: 'test_suite'
warnings.warn(msg)
running config
dh_auto_build -O--buildsystem=pybuild
I: pybuild base:311: /usr/bin/python3 setup.py build
/usr/lib/python3/dist-packages/setuptools/_distutils/dist.py:261: UserWarning:
Unknown distribution option: 'test_suite'
warnings.warn(msg)
running build
running build_py
creating /<<PKGBUILDDIR>>/.pybuild/cpython3_3.12_pyautogui/build/pyautogui
copying pyautogui/_pyautogui_osx.py ->
/<<PKGBUILDDIR>>/.pybuild/cpython3_3.12_pyautogui/build/pyautogui
copying pyautogui/__init__.py ->
/<<PKGBUILDDIR>>/.pybuild/cpython3_3.12_pyautogui/build/pyautogui
copying pyautogui/_pyautogui_win.py ->
/<<PKGBUILDDIR>>/.pybuild/cpython3_3.12_pyautogui/build/pyautogui
copying pyautogui/_pyautogui_java.py ->
/<<PKGBUILDDIR>>/.pybuild/cpython3_3.12_pyautogui/build/pyautogui
copying pyautogui/_pyautogui_x11.py ->
/<<PKGBUILDDIR>>/.pybuild/cpython3_3.12_pyautogui/build/pyautogui
copying pyautogui/__main__.py ->
/<<PKGBUILDDIR>>/.pybuild/cpython3_3.12_pyautogui/build/pyautogui
dh_auto_test -O--buildsystem=pybuild
I: pybuild base:311: cd
'/<<PKGBUILDDIR>>/.pybuild/cpython3_3.12_pyautogui/build'; python3.12 -m pytest
-k 'not TestKeyboard'
============================= test session starts ==============================
platform linux -- Python 3.12.7, pytest-8.3.3, pluggy-1.5.0
rootdir: /<<PKGBUILDDIR>>
plugins: typeguard-4.3.0, xvfb-3.0.0
collected 28 items / 8 deselected / 20 selected
tests/test_pyautogui.py .....F.............F [100%]
=================================== FAILURES ===================================
__________________ TestHelperFunctions.test__normalizeXYArgs ___________________
def grab(
bbox: tuple[int, int, int, int] | None = None,
include_layered_windows: bool = False,
all_screens: bool = False,
xdisplay: str | 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 bbox:
left, top, right, bottom = bbox
args += ["-R", f"{left},{top},{right-left},{bottom-top}"]
subprocess.call(args + ["-x", filepath])
im = Image.open(filepath)
im.load()
os.unlink(filepath)
if bbox:
im_resized = im.resize((right - left, bottom - top))
im.close()
return im_resized
return im
elif sys.platform == "win32":
offset, size, data = Image.core.grabscreen_win32(
include_layered_windows, all_screens
)
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: unsupported bit depth: 16
/usr/lib/python3/dist-packages/PIL/ImageGrab.py:78: OSError
During handling of the above exception, another exception occurred:
self = <test_pyautogui.TestHelperFunctions testMethod=test__normalizeXYArgs>
def test__normalizeXYArgs(self):
self.assertEqual(pyautogui._normalizeXYArgs(1, 2), pyautogui.Point(x=1,
y=2))
self.assertEqual(pyautogui._normalizeXYArgs((1, 2), None),
pyautogui.Point(x=1, y=2))
self.assertEqual(pyautogui._normalizeXYArgs([1, 2], None),
pyautogui.Point(x=1, y=2))
pyautogui.useImageNotFoundException()
with self.assertRaises(pyautogui.ImageNotFoundException):
pyautogui._normalizeXYArgs("100x100blueimage.png", None)
/<<PKGBUILDDIR>>/.pybuild/cpython3_3.12_pyautogui/build/tests/test_pyautogui.py:267:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
/<<PKGBUILDDIR>>/.pybuild/cpython3_3.12_pyautogui/build/pyautogui/__init__.py:663:
in _normalizeXYArgs
location = locateOnScreen(firstArg)
/<<PKGBUILDDIR>>/.pybuild/cpython3_3.12_pyautogui/build/pyautogui/__init__.py:172:
in wrapper
return wrappedFunction(*args, **kwargs)
/<<PKGBUILDDIR>>/.pybuild/cpython3_3.12_pyautogui/build/pyautogui/__init__.py:210:
in locateOnScreen
return pyscreeze.locateOnScreen(*args, **kwargs)
/usr/lib/python3/dist-packages/pyscreeze/__init__.py:404: in locateOnScreen
screenshotIm = screenshot(region=None)
/usr/lib/python3/dist-packages/pyscreeze/__init__.py:603: in _screenshot_linux
im = ImageGrab.grab() # use Pillow's grab() for Pillow 9.2.0 and later.
/usr/lib/python3/dist-packages/PIL/ImageGrab.py:88: in grab
im = Image.open(filepath)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
def open(
fp: StrOrBytesPath | IO[bytes],
mode: Literal["r"] = "r",
formats: list[str] | tuple[str, ...] | None = None,
) -> ImageFile.ImageFile:
"""
Opens and identifies the given image file.
This is a lazy operation; this function identifies the file, but
the file remains open and the actual image data is not read from
the file until you try to process the data (or call the
:py:meth:`~PIL.Image.Image.load` method). See
:py:func:`~PIL.Image.new`. See :ref:`file-handling`.
:param fp: A filename (string), os.PathLike object or a file object.
The file object must implement ``file.read``,
``file.seek``, and ``file.tell`` methods,
and be opened in binary mode. The file object will also seek to zero
before reading.
:param mode: The mode. If given, this argument must be "r".
:param formats: A list or tuple of formats to attempt to load the file
in.
This can be used to restrict the set of formats checked.
Pass ``None`` to try all supported formats. You can print the set of
available formats by running ``python3 -m PIL`` or using
the :py:func:`PIL.features.pilinfo` function.
:returns: An :py:class:`~PIL.Image.Image` object.
:exception FileNotFoundError: If the file cannot be found.
:exception PIL.UnidentifiedImageError: If the image cannot be opened and
identified.
:exception ValueError: If the ``mode`` is not "r", or if a ``StringIO``
instance is used for ``fp``.
:exception TypeError: If ``formats`` is not ``None``, a list or a tuple.
"""
if mode != "r":
msg = f"bad mode {repr(mode)}" # type: ignore[unreachable]
raise ValueError(msg)
elif isinstance(fp, io.StringIO):
msg = ( # type: ignore[unreachable]
"StringIO cannot be used to open an image. "
"Binary data must be used instead."
)
raise ValueError(msg)
if formats is None:
formats = ID
elif not isinstance(formats, (list, tuple)):
msg = "formats must be a list or tuple" # type: ignore[unreachable]
raise TypeError(msg)
exclusive_fp = False
filename: str | bytes = ""
if is_path(fp):
filename = os.path.realpath(os.fspath(fp))
if filename:
fp = builtins.open(filename, "rb")
exclusive_fp = True
else:
fp = cast(IO[bytes], fp)
try:
fp.seek(0)
except (AttributeError, io.UnsupportedOperation):
fp = io.BytesIO(fp.read())
exclusive_fp = True
prefix = fp.read(16)
preinit()
warning_messages: list[str] = []
def _open_core(
fp: IO[bytes],
filename: str | bytes,
prefix: bytes,
formats: list[str] | tuple[str, ...],
) -> ImageFile.ImageFile | None:
for i in formats:
i = i.upper()
if i not in OPEN:
init()
try:
factory, accept = OPEN[i]
result = not accept or accept(prefix)
if isinstance(result, str):
warning_messages.append(result)
elif result:
fp.seek(0)
im = factory(fp, filename)
_decompression_bomb_check(im.size)
return im
except (SyntaxError, IndexError, TypeError, struct.error) as e:
if WARN_POSSIBLE_FORMATS:
warning_messages.append(i + " opening failed. " +
str(e))
except BaseException:
if exclusive_fp:
fp.close()
raise
return None
im = _open_core(fp, filename, prefix, formats)
if im is None and formats is ID:
checked_formats = ID.copy()
if init():
im = _open_core(
fp,
filename,
prefix,
tuple(format for format in formats if format not in
checked_formats),
)
if im:
im._exclusive_fp = exclusive_fp
return im
if exclusive_fp:
fp.close()
for message in warning_messages:
warnings.warn(message)
msg = "cannot identify image file %r" % (filename if filename else fp)
raise UnidentifiedImageError(msg)
E PIL.UnidentifiedImageError: cannot identify image file
'/tmp/tmpvlbevjej.png'
/usr/lib/python3/dist-packages/PIL/Image.py:3498: UnidentifiedImageError
----------------------------- Captured stderr call -----------------------------
(gnome-screenshot:40360): GLib-GIO-CRITICAL **: 09:22:08.866:
g_dbus_connection_call_sync_internal: assertion 'G_IS_DBUS_CONNECTION
(connection)' failed
** Message: 09:22:08.866: Unable to use GNOME Shell's builtin screenshot
interface, resorting to fallback X11.
_________________ TestPyScreezeFunctions.test_locateFunctions __________________
def grab(
bbox: tuple[int, int, int, int] | None = None,
include_layered_windows: bool = False,
all_screens: bool = False,
xdisplay: str | 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 bbox:
left, top, right, bottom = bbox
args += ["-R", f"{left},{top},{right-left},{bottom-top}"]
subprocess.call(args + ["-x", filepath])
im = Image.open(filepath)
im.load()
os.unlink(filepath)
if bbox:
im_resized = im.resize((right - left, bottom - top))
im.close()
return im_resized
return im
elif sys.platform == "win32":
offset, size, data = Image.core.grabscreen_win32(
include_layered_windows, all_screens
)
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: unsupported bit depth: 16
/usr/lib/python3/dist-packages/PIL/ImageGrab.py:78: OSError
During handling of the above exception, another exception occurred:
self = <test_pyautogui.TestPyScreezeFunctions testMethod=test_locateFunctions>
def test_locateFunctions(self):
# TODO - for now, we only test that the "return None" and "raise
pyautogui.ImageNotFoundException" is raised.
pyautogui.useImageNotFoundException()
with self.assertRaises(pyautogui.ImageNotFoundException):
pyautogui.locate("100x100blueimage.png", "100x100redimage.png")
# Commenting out the locateAll*() functions because they return
generators, even if the image can't be found. Should they instead raise an
exception? This is a question for pyscreeze's design.
# with self.assertRaises(pyautogui.ImageNotFoundException):
# pyautogui.locateAll('100x100blueimage.png', '100x100redimage.png')
# with self.assertRaises(pyautogui.ImageNotFoundException):
# pyautogui.locateAllOnScreen('100x100blueimage.png') # NOTE: This
test fails if there is a blue square visible on the screen.
with self.assertRaises(pyautogui.ImageNotFoundException):
pyautogui.locateOnScreen(
"100x100blueimage.png"
) # NOTE: This test fails if there is a blue square visible on the
screen.
/<<PKGBUILDDIR>>/.pybuild/cpython3_3.12_pyautogui/build/tests/test_pyautogui.py:861:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
/<<PKGBUILDDIR>>/.pybuild/cpython3_3.12_pyautogui/build/pyautogui/__init__.py:172:
in wrapper
return wrappedFunction(*args, **kwargs)
/<<PKGBUILDDIR>>/.pybuild/cpython3_3.12_pyautogui/build/pyautogui/__init__.py:210:
in locateOnScreen
return pyscreeze.locateOnScreen(*args, **kwargs)
/usr/lib/python3/dist-packages/pyscreeze/__init__.py:404: in locateOnScreen
screenshotIm = screenshot(region=None)
/usr/lib/python3/dist-packages/pyscreeze/__init__.py:603: in _screenshot_linux
im = ImageGrab.grab() # use Pillow's grab() for Pillow 9.2.0 and later.
/usr/lib/python3/dist-packages/PIL/ImageGrab.py:88: in grab
im = Image.open(filepath)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
def open(
fp: StrOrBytesPath | IO[bytes],
mode: Literal["r"] = "r",
formats: list[str] | tuple[str, ...] | None = None,
) -> ImageFile.ImageFile:
"""
Opens and identifies the given image file.
This is a lazy operation; this function identifies the file, but
the file remains open and the actual image data is not read from
the file until you try to process the data (or call the
:py:meth:`~PIL.Image.Image.load` method). See
:py:func:`~PIL.Image.new`. See :ref:`file-handling`.
:param fp: A filename (string), os.PathLike object or a file object.
The file object must implement ``file.read``,
``file.seek``, and ``file.tell`` methods,
and be opened in binary mode. The file object will also seek to zero
before reading.
:param mode: The mode. If given, this argument must be "r".
:param formats: A list or tuple of formats to attempt to load the file
in.
This can be used to restrict the set of formats checked.
Pass ``None`` to try all supported formats. You can print the set of
available formats by running ``python3 -m PIL`` or using
the :py:func:`PIL.features.pilinfo` function.
:returns: An :py:class:`~PIL.Image.Image` object.
:exception FileNotFoundError: If the file cannot be found.
:exception PIL.UnidentifiedImageError: If the image cannot be opened and
identified.
:exception ValueError: If the ``mode`` is not "r", or if a ``StringIO``
instance is used for ``fp``.
:exception TypeError: If ``formats`` is not ``None``, a list or a tuple.
"""
if mode != "r":
msg = f"bad mode {repr(mode)}" # type: ignore[unreachable]
raise ValueError(msg)
elif isinstance(fp, io.StringIO):
msg = ( # type: ignore[unreachable]
"StringIO cannot be used to open an image. "
"Binary data must be used instead."
)
raise ValueError(msg)
if formats is None:
formats = ID
elif not isinstance(formats, (list, tuple)):
msg = "formats must be a list or tuple" # type: ignore[unreachable]
raise TypeError(msg)
exclusive_fp = False
filename: str | bytes = ""
if is_path(fp):
filename = os.path.realpath(os.fspath(fp))
if filename:
fp = builtins.open(filename, "rb")
exclusive_fp = True
else:
fp = cast(IO[bytes], fp)
try:
fp.seek(0)
except (AttributeError, io.UnsupportedOperation):
fp = io.BytesIO(fp.read())
exclusive_fp = True
prefix = fp.read(16)
preinit()
warning_messages: list[str] = []
def _open_core(
fp: IO[bytes],
filename: str | bytes,
prefix: bytes,
formats: list[str] | tuple[str, ...],
) -> ImageFile.ImageFile | None:
for i in formats:
i = i.upper()
if i not in OPEN:
init()
try:
factory, accept = OPEN[i]
result = not accept or accept(prefix)
if isinstance(result, str):
warning_messages.append(result)
elif result:
fp.seek(0)
im = factory(fp, filename)
_decompression_bomb_check(im.size)
return im
except (SyntaxError, IndexError, TypeError, struct.error) as e:
if WARN_POSSIBLE_FORMATS:
warning_messages.append(i + " opening failed. " +
str(e))
except BaseException:
if exclusive_fp:
fp.close()
raise
return None
im = _open_core(fp, filename, prefix, formats)
if im is None and formats is ID:
checked_formats = ID.copy()
if init():
im = _open_core(
fp,
filename,
prefix,
tuple(format for format in formats if format not in
checked_formats),
)
if im:
im._exclusive_fp = exclusive_fp
return im
if exclusive_fp:
fp.close()
for message in warning_messages:
warnings.warn(message)
msg = "cannot identify image file %r" % (filename if filename else fp)
raise UnidentifiedImageError(msg)
E PIL.UnidentifiedImageError: cannot identify image file
'/tmp/tmpoe_j9hts.png'
/usr/lib/python3/dist-packages/PIL/Image.py:3498: UnidentifiedImageError
----------------------------- Captured stderr call -----------------------------
(gnome-screenshot:40418): GLib-GIO-CRITICAL **: 09:22:21.216:
g_dbus_connection_call_sync_internal: assertion 'G_IS_DBUS_CONNECTION
(connection)' failed
** Message: 09:22:21.216: Unable to use GNOME Shell's builtin screenshot
interface, resorting to fallback X11.
=============================== warnings summary ===============================
pyautogui/_pyautogui_x11.py:284
/<<PKGBUILDDIR>>/.pybuild/cpython3_3.12_pyautogui/build/pyautogui/_pyautogui_x11.py:284:
SyntaxWarning: invalid escape sequence '\e'
'\e': _display.keysym_to_keycode(Xlib.XK.string_to_keysym('Escape')),
-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=========================== short test summary info ============================
FAILED tests/test_pyautogui.py::TestHelperFunctions::test__normalizeXYArgs - ...
FAILED tests/test_pyautogui.py::TestPyScreezeFunctions::test_locateFunctions
============ 2 failed, 18 passed, 8 deselected, 1 warning in 14.28s ============
E: pybuild pybuild:389: test: plugin distutils failed with: exit code=1: cd
'/<<PKGBUILDDIR>>/.pybuild/cpython3_3.12_pyautogui/build'; python3.12 -m pytest
-k 'not TestKeyboard'
dh_auto_test: error: pybuild --test --test-pytest -i python{version} -p 3.12
returned exit code 13
make: *** [debian/rules:8: build] Error 25
dpkg-buildpackage: error: debian/rules build subprocess returned exit status 2
--------------------------------------------------------------------------------
The above is just how the build ends and not necessarily the most relevant part.
If required, the full build log is available here:
https://people.debian.org/~sanvila/build-logs/202410/
About the archive rebuild: The build was made on virtual machines from AWS,
using sbuild and a reduced chroot with only build-essential packages.
Note: The build does not always fail.
If you could not reproduce the bug please contact me privately, as I
am willing to provide ssh access to a virtual machine where the bug is
fully reproducible.
However, before that, please try GRUB_CMDLINE_LINUX="nr_cpus=1"
because (apparently) the failure rate is higher that way.
Note: pyscreeze fails in a similar way, but I'm not reporting
it yet just in case they are the "same" bug.
In case you decide to disable the flaky tests, the attached patch
works for me.
If this is really a bug in one of the build-depends, please use
reassign and affects, so that this is still visible in the BTS web
page for this package.
Thanks.
--- a/debian/rules
+++ b/debian/rules
@@ -3,6 +3,6 @@
# This file was automatically generated by stdeb 0.10.0 at
# Wed, 11 Sep 2024 19:39:47 +0200
export PYBUILD_NAME=pyautogui
-export PYBUILD_TEST_ARGS=-k 'not TestKeyboard'
+export PYBUILD_TEST_ARGS=-k 'not TestKeyboard and not TestHelperFunctions and
not TestPyScreezeFunctions'
%:
dh $@ --with python3 --buildsystem=pybuild