diff mbox series

python3-click: Fixes for new pytest and flaky ptest

Message ID 20260615104940.567584-1-richard.purdie@linuxfoundation.org
State Accepted, archived
Commit 976beed0875a40d71d0c98d56696c97988684ada
Headers show
Series python3-click: Fixes for new pytest and flaky ptest | expand

Commit Message

Richard Purdie June 15, 2026, 10:49 a.m. UTC
Submit a patch upstream to allow it to work with the new version of pytest.

Also backport a "flaky test" fix which may help issues we're seeing on the
autobuilder.

Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
---
 ...7494c991c9197902fdf4995e11b2da3e9762.patch | 173 ++++++++++++++++++
 .../python/python3-click/pytest-fix.patch     |  29 +++
 .../python/python3-click_8.4.1.bb             |   2 +
 3 files changed, 204 insertions(+)
 create mode 100644 meta/recipes-devtools/python/python3-click/ffcc7494c991c9197902fdf4995e11b2da3e9762.patch
 create mode 100644 meta/recipes-devtools/python/python3-click/pytest-fix.patch

Comments

patchtest@automation.yoctoproject.org June 15, 2026, 11:01 a.m. UTC | #1
Thank you for your submission. Patchtest identified one
or more issues with the patch. Please see the log below for
more information:

---
Testing patch /home/patchtest/share/mboxes/python3-click-Fixes-for-new-pytest-and-flaky-ptest.patch

FAIL: test Signed-off-by presence: A patch file has been added without a Signed-off-by tag: 'ffcc7494c991c9197902fdf4995e11b2da3e9762.patch' (test_patch.TestPatch.test_signed_off_by_presence)

PASS: test CVE tag format (test_patch.TestPatch.test_cve_tag_format)
PASS: test Signed-off-by presence (test_mbox.TestMbox.test_signed_off_by_presence)
PASS: test Upstream-Status presence (test_patch.TestPatch.test_upstream_status_presence_format)
PASS: test author valid (test_mbox.TestMbox.test_author_valid)
PASS: test commit message presence (test_mbox.TestMbox.test_commit_message_presence)
PASS: test commit message user tags (test_mbox.TestMbox.test_commit_message_user_tags)
PASS: test mbox format (test_mbox.TestMbox.test_mbox_format)
PASS: test non-AUH upgrade (test_mbox.TestMbox.test_non_auh_upgrade)
PASS: test shortlog format (test_mbox.TestMbox.test_shortlog_format)
PASS: test shortlog length (test_mbox.TestMbox.test_shortlog_length)
PASS: test target mailing list (test_mbox.TestMbox.test_target_mailing_list)

SKIP: pretest pylint: No python related patches, skipping test (test_python_pylint.PyLint.pretest_pylint)
SKIP: test bugzilla entry format: No bug ID found (test_mbox.TestMbox.test_bugzilla_entry_format)
SKIP: test pylint: No python related patches, skipping test (test_python_pylint.PyLint.test_pylint)
SKIP: test series merge on head: Merge test is disabled for now (test_mbox.TestMbox.test_series_merge_on_head)

---

Please address the issues identified and
submit a new revision of the patch, or alternatively, reply to this
email with an explanation of why the patch should be accepted. If you
believe these results are due to an error in patchtest, please submit a
bug at https://bugzilla.yoctoproject.org/ (use the 'Patchtest' category
under 'Yocto Project Subprojects'). For more information on specific
failures, see: https://wiki.yoctoproject.org/wiki/Patchtest. Thank
you!
diff mbox series

Patch

diff --git a/meta/recipes-devtools/python/python3-click/ffcc7494c991c9197902fdf4995e11b2da3e9762.patch b/meta/recipes-devtools/python/python3-click/ffcc7494c991c9197902fdf4995e11b2da3e9762.patch
new file mode 100644
index 00000000000..e16f84ec9a3
--- /dev/null
+++ b/meta/recipes-devtools/python/python3-click/ffcc7494c991c9197902fdf4995e11b2da3e9762.patch
@@ -0,0 +1,173 @@ 
+"Fix pager test flackiness and add stress tests for echo_via_pager"
+
+From 7eb57cff7cd292fbd526eaf861c8f945ddeb07a3 Mon Sep 17 00:00:00 2001
+From: Kevin Deldycke <kevin@deldycke.com>
+Date: Fri, 22 May 2026 11:13:12 +0200
+Subject: [PATCH] Fix pager test race by raising before yield
+
+Upstream-Status: Backport [https://github.com/pallets/click/commit/ffcc7494c991c9197902fdf4995e11b2da3e9762]
+
+Refs: #3470 #2899
+---
+ pyproject.toml                 |  3 +-
+ src/click/_compat.py           |  1 -
+ tests/test_stream_lifecycle.py |  4 +-
+ tests/test_utils.py            | 79 +++++++++++++++++++++++++++++++---
+ 4 files changed, 78 insertions(+), 9 deletions(-)
+
+diff --git a/pyproject.toml b/pyproject.toml
+index e39ef21055..ed91e5d741 100644
+--- a/pyproject.toml
++++ b/pyproject.toml
+@@ -185,12 +185,11 @@ commands = [[
+ ]]
+ 
+ [tool.tox.env.stress]
+-description = "stress tests for stream lifecycle race conditions"
++description = "high-iteration stress tests for race conditions"
+ commands = [[
+     "pytest", "-v", "--tb=short", "-x", "-m", "stress",
+     "--basetemp={env_tmp_dir}",
+     "--override-ini=addopts=",
+-    "tests/test_stream_lifecycle.py",
+     {replace = "posargs", default = [], extend = true},
+ ]]
+ 
+diff --git a/src/click/_compat.py b/src/click/_compat.py
+index 36c0e53975..134c4f3893 100644
+--- a/src/click/_compat.py
++++ b/src/click/_compat.py
+@@ -12,7 +12,6 @@
+ 
+ CYGWIN = sys.platform.startswith("cygwin")
+ WIN = sys.platform.startswith("win")
+-MAC = sys.platform == "darwin"
+ auto_wrap_for_ansi: t.Callable[[t.TextIO], t.TextIO] | None = None
+ _ansi_re = re.compile(r"\033\[[;?0-9]*[a-zA-Z]")
+ 
+diff --git a/tests/test_stream_lifecycle.py b/tests/test_stream_lifecycle.py
+index 42e26acc34..9f4aa20868 100644
+--- a/tests/test_stream_lifecycle.py
++++ b/tests/test_stream_lifecycle.py
+@@ -484,7 +484,9 @@ def cli():
+ # Category 6: Stress tests - high-iteration reproducers for race conditions
+ #
+ # These are marked with ``pytest.mark.stress`` so they can be included or
+-# excluded independently. The CI workflow runs them in a separate job.
++# excluded independently. The ``tox -e stress`` env collects every
++# ``pytest.mark.stress`` test across the suite (not just this file), so
++# stress regressions for other components live alongside their unit tests.
+ # ---------------------------------------------------------------------------
+ 
+ 
+diff --git a/tests/test_utils.py b/tests/test_utils.py
+index 139cd7324f..1aebf3cc5a 100644
+--- a/tests/test_utils.py
++++ b/tests/test_utils.py
+@@ -16,7 +16,6 @@
+ 
+ import click._termui_impl
+ import click.utils
+-from click._compat import MAC
+ from click._compat import WIN
+ from click._utils import UNSET
+ 
+@@ -286,6 +285,11 @@ def _test_gen_func():
+ 
+ 
+ def _test_gen_func_fails():
++    raise RuntimeError("This is a test.")
++    yield  # unreachable, keeps this a generator function
++
++
++def _test_gen_func_yields_then_fails():
+     yield "test"
+     raise RuntimeError("This is a test.")
+ 
+@@ -315,10 +319,6 @@ def _test_simulate_keyboard_interrupt(file=None):
+ 
+ 
+ @pytest.mark.skipif(WIN, reason="Different behavior on windows.")
+-@pytest.mark.skipif(
+-    MAC and sys.version_info >= (3, 13) and not sys._is_gil_enabled(),
+-    reason="Generator exception tests are flaky in Python 3.14t on macOS.",
+-)
+ @pytest.mark.parametrize(
+     "pager_cmd", ["cat", "cat ", " cat ", "less", " less", " less "]
+ )
+@@ -456,6 +456,75 @@ def test_echo_via_pager(monkeypatch, capfd, pager_cmd, test, tmp_path):
+     )
+ 
+ 
++@pytest.mark.skipif(WIN, reason="Different behavior on windows.")
++def test_echo_via_pager_yields_before_exception(monkeypatch, tmp_path):
++    """A generator that yields then raises: click writes the partial output to
++    the pager stream before propagating the exception.
++
++    The pager file content is intentionally NOT asserted: pipe-drain timing
++    between click and the pager subprocess is outside click's control
++    (#2899, #3470). Spying on ``MaybeStripAnsi.write`` records what click sent
++    to the pager, which is deterministic regardless of scheduling.
++    """
++    monkeypatch.setitem(os.environ, "PAGER", "cat")
++    monkeypatch.setattr(click._termui_impl, "isatty", lambda x: True)
++
++    writes: list[str] = []
++    real_write = click._termui_impl.MaybeStripAnsi.write
++
++    def spy(self, text):
++        writes.append(text)
++        return real_write(self, text)
++
++    monkeypatch.setattr(click._termui_impl.MaybeStripAnsi, "write", spy)
++
++    pager_out_tmp = tmp_path / "pager_out.txt"
++    with (
++        pager_out_tmp.open("w") as f,
++        patch.object(subprocess, "Popen", partial(subprocess.Popen, stdout=f)),
++        pytest.raises(RuntimeError, match="This is a test."),
++    ):
++        click.echo_via_pager(_test_gen_func_yields_then_fails())
++
++    assert "".join(writes) == "test", (
++        f"click should have written the yielded chunk before exception, got {writes!r}"
++    )
++
++
++@pytest.mark.stress
++@pytest.mark.skipif(WIN, reason="Different behavior on windows.")
++@pytest.mark.parametrize("_", range(1000))
++def test_stress_echo_via_pager_exception_cleanup(_, monkeypatch, tmp_path):
++    """Repeated exceptions during ``echo_via_pager`` must not leak subprocesses.
++
++    Regression coverage for the cleanup path in ``_pipepager``'s exception
++    handler (issue #2899, PR #3470). Each iteration spawns a real pager
++    subprocess, raises before any data is written and check there is no leak.
++    """
++    monkeypatch.setitem(os.environ, "PAGER", "cat")
++    monkeypatch.setattr(click._termui_impl, "isatty", lambda x: True)
++
++    spawned: list[subprocess.Popen] = []
++    real_popen = subprocess.Popen
++
++    def tracking_popen(*args, **kwargs):
++        p = real_popen(*args, **kwargs)
++        spawned.append(p)
++        return p
++
++    pager_out_tmp = tmp_path / "pager_out.txt"
++    with (
++        pager_out_tmp.open("w") as f,
++        patch.object(subprocess, "Popen", partial(tracking_popen, stdout=f)),
++        pytest.raises(RuntimeError),
++    ):
++        click.echo_via_pager(_test_gen_func_fails())
++
++    assert spawned, "pager subprocess was never started"
++    for p in spawned:
++        assert p.returncode is not None, "pager subprocess not reaped"
++
++
+ def test_echo_color_flag(monkeypatch, capfd):
+     isatty = True
+     monkeypatch.setattr(click._compat, "isatty", lambda x: isatty)
diff --git a/meta/recipes-devtools/python/python3-click/pytest-fix.patch b/meta/recipes-devtools/python/python3-click/pytest-fix.patch
new file mode 100644
index 00000000000..662ad8aae9d
--- /dev/null
+++ b/meta/recipes-devtools/python/python3-click/pytest-fix.patch
@@ -0,0 +1,29 @@ 
+Fix an error with newer versions of pytest (9.1.0) by converting the generator into a tuple:
+
+E   pytest.PytestRemovedIn10Warning: Passing a non-Collection iterable to parametrize is deprecated.
+E   Test: tests/test_basic.py::test_boolean_conversion, argvalues type: chain
+E   Please convert to a list or tuple.
+E   See https://docs.pytest.org/en/stable/deprecations.html#parametrize-iterators
+ERROR: tests/test_basic.py:tests/test_basic.py
+
+Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
+
+Upstream-Status: Submitted [https://github.com/pallets/click/pull/3597]
+
+Index: click-8.3.3/tests/test_basic.py
+===================================================================
+--- click-8.3.3.orig/tests/test_basic.py
++++ click-8.3.3/tests/test_basic.py
+@@ -258,10 +258,10 @@ def test_boolean_flag(runner, default, a
+ 
+ @pytest.mark.parametrize(
+     ("value", "expect"),
+-    chain(
++    tuple(chain(
+         ((x, "True") for x in ("1", "true", "t", "yes", "y", "on")),
+         ((x, "False") for x in ("0", "false", "f", "no", "n", "off")),
+-    ),
++    )),
+ )
+ def test_boolean_conversion(runner, value, expect):
+     @click.command()
diff --git a/meta/recipes-devtools/python/python3-click_8.4.1.bb b/meta/recipes-devtools/python/python3-click_8.4.1.bb
index 0669cc65108..53c75c333c2 100644
--- a/meta/recipes-devtools/python/python3-click_8.4.1.bb
+++ b/meta/recipes-devtools/python/python3-click_8.4.1.bb
@@ -8,6 +8,8 @@  HOMEPAGE = "http://click.pocoo.org/"
 LICENSE = "BSD-3-Clause"
 LIC_FILES_CHKSUM = "file://LICENSE.txt;md5=1fa98232fd645608937a0fdc82e999b8"
 
+SRC_URI += "file://pytest-fix.patch"
+SRC_URI += "file://ffcc7494c991c9197902fdf4995e11b2da3e9762.patch"
 SRC_URI[sha256sum] = "918b5633eddf6b41c32d4f454bf0de810065c74e3f7dbf8ee5452f8be88d3e96"
 
 inherit pypi python_flit_core ptest-python-pytest