diff --git a/.fmf/version b/.fmf/version
new file mode 100644
index 0000000..d00491f
--- /dev/null
+++ b/.fmf/version
@@ -0,0 +1 @@
+1
diff --git a/.gitignore b/.gitignore
index e69de29..e03cf67 100644
--- a/.gitignore
+++ b/.gitignore
@@ -0,0 +1,5 @@
+/pytest-*.zip
+/pytest-*.tar.gz
+/pytest-*/
+/results_*/
+*.rpm
diff --git a/13291.patch b/13291.patch
new file mode 100644
index 0000000..1f0ed10
--- /dev/null
+++ b/13291.patch
@@ -0,0 +1,31 @@
+From b7854561993d00b8dddf3f43ce6b042b4111fa4c Mon Sep 17 00:00:00 2001
+From: jakkdl
+Date: Wed, 12 Mar 2025 15:10:29 +0100
+Subject: [PATCH] fix attrs==25.2.0 compatibility
+
+---
+ changelog/13291.bugfix.rst | 1 +
+ src/_pytest/assertion/util.py | 2 +-
+ 2 files changed, 2 insertions(+), 1 deletion(-)
+ create mode 100644 changelog/13291.bugfix.rst
+
+diff --git a/changelog/13291.bugfix.rst b/changelog/13291.bugfix.rst
+new file mode 100644
+index 00000000000..03ce06b697a
+--- /dev/null
++++ b/changelog/13291.bugfix.rst
+@@ -0,0 +1 @@
++Fixed ``repr`` of ``attrs`` objects in assertion failure messages when using ``attrs>=25.2``.
+diff --git a/src/_pytest/assertion/util.py b/src/_pytest/assertion/util.py
+index 30aee185d57..c545e6cd20c 100644
+--- a/src/_pytest/assertion/util.py
++++ b/src/_pytest/assertion/util.py
+@@ -169,7 +169,7 @@ def has_default_eq(
+ code_filename = obj.__eq__.__code__.co_filename
+
+ if isattrs(obj):
+- return "attrs generated eq" in code_filename
++ return "attrs generated " in code_filename
+
+ return code_filename == "" # data class
+ return True
diff --git a/13440.patch b/13440.patch
new file mode 100644
index 0000000..84234f5
--- /dev/null
+++ b/13440.patch
@@ -0,0 +1,617 @@
+From a3a606005525922d35639efc3009db47fc50cbce Mon Sep 17 00:00:00 2001
+From: Thomas Grainger
+Date: Mon, 26 May 2025 15:41:26 +0100
+Subject: [PATCH 01/19] test on py3.14
+
+---
+ .github/workflows/test.yml | 14 ++++++++++++++
+ 1 file changed, 14 insertions(+)
+
+diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
+index 33dede6..9354ddd 100644
+--- a/.github/workflows/test.yml
++++ b/.github/workflows/test.yml
+@@ -112,6 +112,10 @@ jobs:
+ python: "3.13-dev"
+ os: windows-latest
+ tox_env: "py313"
++ - name: "windows-py314"
++ python: "3.14"
++ os: windows-latest
++ tox_env: "py314"
+
+ - name: "ubuntu-py38"
+ python: "3.8"
+@@ -149,6 +153,11 @@ jobs:
+ os: ubuntu-latest
+ tox_env: "py313-pexpect"
+ use_coverage: true
++ - name: "ubuntu-py314"
++ python: "3.14"
++ os: ubuntu-latest
++ tox_env: "py314"
++ use_coverage: true
+ - name: "ubuntu-pypy3"
+ python: "pypy-3.9"
+ os: ubuntu-latest
+@@ -175,6 +184,10 @@ jobs:
+ python: "3.13-dev"
+ os: macos-latest
+ tox_env: "py313-xdist"
++ - name: "macos-py314"
++ python: "3.14"
++ os: macos-latest
++ tox_env: "py314-xdist"
+
+ - name: "plugins"
+ python: "3.12"
+@@ -224,6 +237,7 @@ jobs:
+ with:
+ python-version: ${{ matrix.python }}
+ check-latest: ${{ endsWith(matrix.python, '-dev') }}
++ allow-prereleases: true
+
+ - name: Install dependencies
+ run: |
+
+From e8e2899d139ec4248621c113da881230fefc9cca Mon Sep 17 00:00:00 2001
+From: Thomas Grainger
+Date: Mon, 26 May 2025 15:42:46 +0100
+Subject: [PATCH 02/19] add news
+
+---
+ changelog/13308.improvement.rst | 1 +
+ 1 file changed, 1 insertion(+)
+ create mode 100644 changelog/13308.improvement.rst
+
+diff --git a/changelog/13308.improvement.rst b/changelog/13308.improvement.rst
+new file mode 100644
+index 0000000..9063159
+--- /dev/null
++++ b/changelog/13308.improvement.rst
+@@ -0,0 +1 @@
++support Python 3.14
+
+From 7494a7d88d38450e6864f84cbdb4066029cea864 Mon Sep 17 00:00:00 2001
+From: Thomas Grainger
+Date: Mon, 26 May 2025 15:43:44 +0100
+Subject: [PATCH 03/19] add 314 to tox.ini
+
+---
+ tox.ini | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/tox.ini b/tox.ini
+index 1a6ab34..6f49b80 100644
+--- a/tox.ini
++++ b/tox.ini
+@@ -10,6 +10,7 @@ envlist =
+ py311
+ py312
+ py313
++ py314
+ pypy3
+ py38-{pexpect,xdist,unittestextras,numpy,pluggymain,pylib}
+ doctesting
+
+From 93915f78953d939319e9dfd828f6284611c3b786 Mon Sep 17 00:00:00 2001
+From: Thomas Grainger
+Date: Mon, 26 May 2025 15:56:22 +0100
+Subject: [PATCH 04/19] fix ResourceWarning on pastebin http failures
+
+---
+ src/_pytest/pastebin.py | 8 ++++++--
+ 1 file changed, 6 insertions(+), 2 deletions(-)
+
+diff --git a/src/_pytest/pastebin.py b/src/_pytest/pastebin.py
+index 69c011e..4887620 100644
+--- a/src/_pytest/pastebin.py
++++ b/src/_pytest/pastebin.py
+@@ -78,6 +78,7 @@ def create_new_paste(contents: str | bytes) -> str:
+ import re
+ from urllib.parse import urlencode
+ from urllib.request import urlopen
++ from urllib.error import HTTPError
+
+ params = {"code": contents, "lexer": "text", "expiry": "1week"}
+ url = "https://bpa.st"
+@@ -85,8 +86,11 @@ def create_new_paste(contents: str | bytes) -> str:
+ response: str = (
+ urlopen(url, data=urlencode(params).encode("ascii")).read().decode("utf-8")
+ )
+- except OSError as exc_info: # urllib errors
+- return f"bad response: {exc_info}"
++ except HTTPError as e: # urllib.error errors
++ with e:
++ return f"bad response: {e}"
++ except OSError as e: # urllib errors
++ return f"bad response: {e}"
+ m = re.search(r'href="/raw/(\w+)"', response)
+ if m:
+ return f"{url}/show/{m.group(1)}"
+
+From 2e94b15467f4bea6f280a0f2fbb769327cdc2ca2 Mon Sep 17 00:00:00 2001
+From: Thomas Grainger
+Date: Mon, 26 May 2025 15:56:41 +0100
+Subject: [PATCH 05/19] fix ResourceWarning on pytest.raises with urllib.error
+
+---
+ testing/python/raises.py | 4 +++-
+ 1 file changed, 3 insertions(+), 1 deletion(-)
+
+diff --git a/testing/python/raises.py b/testing/python/raises.py
+index 2011c81..df4ab0b 100644
+--- a/testing/python/raises.py
++++ b/testing/python/raises.py
+@@ -335,5 +335,7 @@ class TestRaises:
+ """
+ from urllib.error import HTTPError
+
+- with pytest.raises(HTTPError, match="Not Found"):
++ with pytest.raises(HTTPError, match="Not Found") as exc_info:
+ raise HTTPError(code=404, msg="Not Found", fp=None, hdrs=None, url="") # type: ignore [arg-type]
++ with exc_info.value:
++ pass
+
+From ac469d125d26b5569d5c8f440f3445aa41c37d8c Mon Sep 17 00:00:00 2001
+From: "pre-commit-ci[bot]"
+ <66853113+pre-commit-ci[bot]@users.noreply.github.com>
+Date: Mon, 26 May 2025 14:57:08 +0000
+Subject: [PATCH 06/19] auto fixes from pre-commit.com hooks
+
+for more information, see https://pre-commit.ci
+---
+ src/_pytest/pastebin.py | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/_pytest/pastebin.py b/src/_pytest/pastebin.py
+index 4887620..86519f6 100644
+--- a/src/_pytest/pastebin.py
++++ b/src/_pytest/pastebin.py
+@@ -76,9 +76,9 @@ def create_new_paste(contents: str | bytes) -> str:
+ :returns: URL to the pasted contents, or an error message.
+ """
+ import re
++ from urllib.error import HTTPError
+ from urllib.parse import urlencode
+ from urllib.request import urlopen
+- from urllib.error import HTTPError
+
+ params = {"code": contents, "lexer": "text", "expiry": "1week"}
+ url = "https://bpa.st"
+
+From 853b7dcc6c93f2f1ad15ab3d87404ad86af03232 Mon Sep 17 00:00:00 2001
+From: Thomas Grainger
+Date: Mon, 26 May 2025 16:14:41 +0100
+Subject: [PATCH 07/19] pass real types for HTTPError so it works in cmgr
+
+---
+ testing/python/raises.py | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/testing/python/raises.py b/testing/python/raises.py
+index df4ab0b..0708d7f 100644
+--- a/testing/python/raises.py
++++ b/testing/python/raises.py
+@@ -1,6 +1,7 @@
+ # mypy: allow-untyped-defs
+ from __future__ import annotations
+
++import io
+ import re
+ import sys
+
+@@ -333,9 +334,12 @@ class TestRaises:
+
+ https://github.com/python/cpython/issues/98778
+ """
++ from email.message import Message
+ from urllib.error import HTTPError
+
+ with pytest.raises(HTTPError, match="Not Found") as exc_info:
+- raise HTTPError(code=404, msg="Not Found", fp=None, hdrs=None, url="") # type: ignore [arg-type]
++ raise HTTPError(
++ code=404, msg="Not Found", fp=io.BytesIO(), hdrs=Message(), url=""
++ )
+ with exc_info.value:
+ pass
+
+From 1e06df0808eacea7d279723bd90e2c5ee0bba506 Mon Sep 17 00:00:00 2001
+From: Thomas Grainger
+Date: Mon, 26 May 2025 16:15:04 +0100
+Subject: [PATCH 08/19] xfail test_raises_bdbquit_with_eoferror
+
+---
+ testing/test_debugging.py | 1 +
+ 1 file changed, 1 insertion(+)
+
+diff --git a/testing/test_debugging.py b/testing/test_debugging.py
+index 73a4b76..8ab45bd 100644
+--- a/testing/test_debugging.py
++++ b/testing/test_debugging.py
+@@ -1279,6 +1279,7 @@ def test_pdbcls_via_local_module(pytester: Pytester) -> None:
+ result.stdout.fnmatch_lines(["*runcall_called*", "* 1 passed in *"])
+
+
++@pytest.mark.xfail(sys.version_info >= (3, 14), reason="I don't know why this fails")
+ def test_raises_bdbquit_with_eoferror(pytester: Pytester) -> None:
+ """It is not guaranteed that DontReadFromInput's read is called."""
+ p1 = pytester.makepyfile(
+
+From 7ba9aa53d7472b9d0c1ac7242c5aa7b56df4c544 Mon Sep 17 00:00:00 2001
+From: Thomas Grainger
+Date: Mon, 26 May 2025 17:14:02 +0100
+Subject: [PATCH 09/19] fix message for unraisable exceptions
+
+---
+ testing/test_unraisableexception.py | 15 ++++++++++++---
+ 1 file changed, 12 insertions(+), 3 deletions(-)
+
+diff --git a/testing/test_unraisableexception.py b/testing/test_unraisableexception.py
+index a15c754..d8490b5 100644
+--- a/testing/test_unraisableexception.py
++++ b/testing/test_unraisableexception.py
+@@ -8,6 +8,15 @@ import pytest
+
+ PYPY = hasattr(sys, "pypy_version_info")
+
++UNRAISABLE_LINE = (
++ (
++ " * PytestUnraisableExceptionWarning: Exception ignored while calling "
++ "deallocator : None"
++ )
++ if sys.version_info >= (3, 14)
++ else " * PytestUnraisableExceptionWarning: Exception ignored in: "
++)
++
+
+ @pytest.mark.skipif(PYPY, reason="garbage-collection differences make this flaky")
+ @pytest.mark.filterwarnings("default::pytest.PytestUnraisableExceptionWarning")
+@@ -32,7 +41,7 @@ def test_unraisable(pytester: Pytester) -> None:
+ [
+ "*= warnings summary =*",
+ "test_it.py::test_it",
+- " * PytestUnraisableExceptionWarning: Exception ignored in: ",
++ UNRAISABLE_LINE,
+ " ",
+ " Traceback (most recent call last):",
+ " ValueError: del is broken",
+@@ -69,7 +78,7 @@ def test_unraisable_in_setup(pytester: Pytester) -> None:
+ [
+ "*= warnings summary =*",
+ "test_it.py::test_it",
+- " * PytestUnraisableExceptionWarning: Exception ignored in: ",
++ UNRAISABLE_LINE,
+ " ",
+ " Traceback (most recent call last):",
+ " ValueError: del is broken",
+@@ -107,7 +116,7 @@ def test_unraisable_in_teardown(pytester: Pytester) -> None:
+ [
+ "*= warnings summary =*",
+ "test_it.py::test_it",
+- " * PytestUnraisableExceptionWarning: Exception ignored in: ",
++ UNRAISABLE_LINE,
+ " ",
+ " Traceback (most recent call last):",
+ " ValueError: del is broken",
+
+From 66a5284096584943f611f607358a2c29fac61d55 Mon Sep 17 00:00:00 2001
+From: Thomas Grainger
+Date: Mon, 26 May 2025 20:27:45 +0100
+Subject: [PATCH 10/19] use improved prog default value for
+ argparse.ArgumentParser
+
+---
+ testing/test_parseopt.py | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/testing/test_parseopt.py b/testing/test_parseopt.py
+index 14e2b5f..36db7b1 100644
+--- a/testing/test_parseopt.py
++++ b/testing/test_parseopt.py
+@@ -28,7 +28,7 @@ class TestParser:
+
+ def test_custom_prog(self, parser: parseopt.Parser) -> None:
+ """Custom prog can be set for `argparse.ArgumentParser`."""
+- assert parser._getparser().prog == os.path.basename(sys.argv[0])
++ assert parser._getparser().prog == argparse.ArgumentParser().prog
+ parser.prog = "custom-prog"
+ assert parser._getparser().prog == "custom-prog"
+
+From 394456931a51e06c68a9a653344483f1e7c24a19 Mon Sep 17 00:00:00 2001
+From: Thomas Grainger
+Date: Mon, 26 May 2025 20:39:57 +0100
+Subject: [PATCH 11/19] Update testing/python/raises.py
+
+---
+ testing/python/raises.py | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+diff --git a/testing/python/raises.py b/testing/python/raises.py
+index 0708d7f..ed052a3 100644
+--- a/testing/python/raises.py
++++ b/testing/python/raises.py
+@@ -341,5 +341,4 @@ class TestRaises:
+ raise HTTPError(
+ code=404, msg="Not Found", fp=io.BytesIO(), hdrs=Message(), url=""
+ )
+- with exc_info.value:
+- pass
++ exc_info.value.close() # avoid a resource warning
+
+From 90ca5cf7080f69d89cdf2badc8f9044753a421e6 Mon Sep 17 00:00:00 2001
+From: Thomas Grainger
+Date: Tue, 27 May 2025 09:49:10 +0100
+Subject: [PATCH 12/19] Update testing/test_debugging.py
+
+---
+ testing/test_debugging.py | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/testing/test_debugging.py b/testing/test_debugging.py
+index 8ab45bd..52a35db 100644
+--- a/testing/test_debugging.py
++++ b/testing/test_debugging.py
+@@ -1279,7 +1279,7 @@ def test_pdbcls_via_local_module(pytester: Pytester) -> None:
+ result.stdout.fnmatch_lines(["*runcall_called*", "* 1 passed in *"])
+
+
+-@pytest.mark.xfail(sys.version_info >= (3, 14), reason="I don't know why this fails")
++@pytest.mark.xfail(sys.version_info >= (3, 14), reason="see https://github.com/python/cpython/issues/124703")
+ def test_raises_bdbquit_with_eoferror(pytester: Pytester) -> None:
+ """It is not guaranteed that DontReadFromInput's read is called."""
+ p1 = pytester.makepyfile(
+
+From e7db19dcbe254f8bebcb4f6665ef43f4fb66b2c7 Mon Sep 17 00:00:00 2001
+From: "pre-commit-ci[bot]"
+ <66853113+pre-commit-ci[bot]@users.noreply.github.com>
+Date: Tue, 27 May 2025 08:49:33 +0000
+Subject: [PATCH 13/19] auto fixes from pre-commit.com hooks
+
+for more information, see https://pre-commit.ci
+---
+ testing/test_debugging.py | 5 ++++-
+ 1 file changed, 4 insertions(+), 1 deletion(-)
+
+diff --git a/testing/test_debugging.py b/testing/test_debugging.py
+index 52a35db..f4780f8 100644
+--- a/testing/test_debugging.py
++++ b/testing/test_debugging.py
+@@ -1279,7 +1279,10 @@ def test_pdbcls_via_local_module(pytester: Pytester) -> None:
+ result.stdout.fnmatch_lines(["*runcall_called*", "* 1 passed in *"])
+
+
+-@pytest.mark.xfail(sys.version_info >= (3, 14), reason="see https://github.com/python/cpython/issues/124703")
++@pytest.mark.xfail(
++ sys.version_info >= (3, 14),
++ reason="see https://github.com/python/cpython/issues/124703",
++)
+ def test_raises_bdbquit_with_eoferror(pytester: Pytester) -> None:
+ """It is not guaranteed that DontReadFromInput's read is called."""
+ p1 = pytester.makepyfile(
+
+From bc5c45081925dd345f9f7545a5e113012031a922 Mon Sep 17 00:00:00 2001
+From: jakkdl
+Date: Tue, 27 May 2025 11:46:00 +0200
+Subject: [PATCH 14/19] be more explicit in debugging xfail
+
+---
+ testing/test_debugging.py | 3 ++-
+ 1 file changed, 2 insertions(+), 1 deletion(-)
+
+diff --git a/testing/test_debugging.py b/testing/test_debugging.py
+index f4780f8..01ff22b 100644
+--- a/testing/test_debugging.py
++++ b/testing/test_debugging.py
+@@ -1281,7 +1281,7 @@ def test_pdbcls_via_local_module(pytester: Pytester) -> None:
+
+ @pytest.mark.xfail(
+ sys.version_info >= (3, 14),
+- reason="see https://github.com/python/cpython/issues/124703",
++ reason="C-D now quits the test session, rather than failing the test. See https://github.com/python/cpython/issues/124703",
+ )
+ def test_raises_bdbquit_with_eoferror(pytester: Pytester) -> None:
+ """It is not guaranteed that DontReadFromInput's read is called."""
+@@ -1297,6 +1297,7 @@ def test_raises_bdbquit_with_eoferror(pytester: Pytester) -> None:
+ """
+ )
+ result = pytester.runpytest(str(p1))
++ result.assert_outcomes(failed=1)
+ result.stdout.fnmatch_lines(["E *BdbQuit", "*= 1 failed in*"])
+ assert result.ret == 1
+
+From 8ff6d3e4677315ac87bfbcba3d0bbf357b5db5df Mon Sep 17 00:00:00 2001
+From: Thomas Grainger
+Date: Tue, 27 May 2025 12:34:25 +0100
+Subject: [PATCH 15/19] Update changelog/13308.improvement.rst
+
+Co-authored-by: Bruno Oliveira
+---
+ changelog/13308.improvement.rst | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/changelog/13308.improvement.rst b/changelog/13308.improvement.rst
+index 9063159..70018c6 100644
+--- a/changelog/13308.improvement.rst
++++ b/changelog/13308.improvement.rst
+@@ -1 +1 @@
+-support Python 3.14
++Added official support for Python 3.14.
+
+From ac3bc419f6f6a504d93e7570cf899769a9a061bd Mon Sep 17 00:00:00 2001
+From: Thomas Grainger
+Date: Tue, 27 May 2025 12:35:01 +0100
+Subject: [PATCH 16/19] Update src/_pytest/pastebin.py
+
+---
+ src/_pytest/pastebin.py | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/src/_pytest/pastebin.py b/src/_pytest/pastebin.py
+index 86519f6..311f72a 100644
+--- a/src/_pytest/pastebin.py
++++ b/src/_pytest/pastebin.py
+@@ -87,7 +87,7 @@ def create_new_paste(contents: str | bytes) -> str:
+ urlopen(url, data=urlencode(params).encode("ascii")).read().decode("utf-8")
+ )
+ except HTTPError as e: # urllib.error errors
+- with e:
++ with e: # HTTPErrors are also http responses that must be closed!
+ return f"bad response: {e}"
+ except OSError as e: # urllib errors
+ return f"bad response: {e}"
+
+From 94f67ef625c654bcc52b4008864fef2db6d4ae42 Mon Sep 17 00:00:00 2001
+From: Thomas Grainger
+Date: Wed, 28 May 2025 09:17:53 +0100
+Subject: [PATCH 17/19] add 3.14 trove classifier
+
+---
+ pyproject.toml | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/pyproject.toml b/pyproject.toml
+index ff27906..ab128a9 100644
+--- a/pyproject.toml
++++ b/pyproject.toml
+@@ -38,6 +38,8 @@ classifiers = [
+ "Programming Language :: Python :: 3.10",
+ "Programming Language :: Python :: 3.11",
+ "Programming Language :: Python :: 3.12",
++ "Programming Language :: Python :: 3.13",
++ "Programming Language :: Python :: 3.14",
+ "Topic :: Software Development :: Libraries",
+ "Topic :: Software Development :: Testing",
+ "Topic :: Utilities",
+@@ -319,6 +321,7 @@ ignore = "W009"
+
+ [tool.pyproject-fmt]
+ indent = 4
++max_supported_python = "3.14"
+
+ [tool.pytest.ini_options]
+ minversion = "2.0"
+
+From 70353bab4c8d5242f442bb63de79f3eb694d998a Mon Sep 17 00:00:00 2001
+From: Thomas Grainger
+Date: Thu, 29 May 2025 16:46:36 +0100
+Subject: [PATCH 18/19] patch coverage
+
+---
+ src/_pytest/pastebin.py | 4 ++--
+ testing/test_pastebin.py | 47 +++++++++++++++++++++++-----------------
+ 2 files changed, 29 insertions(+), 22 deletions(-)
+
+diff --git a/src/_pytest/pastebin.py b/src/_pytest/pastebin.py
+index 311f72a..da6fd94 100644
+--- a/src/_pytest/pastebin.py
++++ b/src/_pytest/pastebin.py
+@@ -86,10 +86,10 @@ def create_new_paste(contents: str | bytes) -> str:
+ response: str = (
+ urlopen(url, data=urlencode(params).encode("ascii")).read().decode("utf-8")
+ )
+- except HTTPError as e: # urllib.error errors
++ except HTTPError as e:
+ with e: # HTTPErrors are also http responses that must be closed!
+ return f"bad response: {e}"
+- except OSError as e: # urllib errors
++ except OSError as e: # eg urllib.error.URLError
+ return f"bad response: {e}"
+ m = re.search(r'href="/raw/(\w+)"', response)
+ if m:
+diff --git a/testing/test_pastebin.py b/testing/test_pastebin.py
+index 8fdd60b..9b928e0 100644
+--- a/testing/test_pastebin.py
++++ b/testing/test_pastebin.py
+@@ -3,6 +3,7 @@ from __future__ import annotations
+
+ import email.message
+ import io
++from unittest import mock
+
+ from _pytest.monkeypatch import MonkeyPatch
+ from _pytest.pytester import Pytester
+@@ -90,23 +91,6 @@ class TestPaste:
+ def pastebin(self, request):
+ return request.config.pluginmanager.getplugin("pastebin")
+
+- @pytest.fixture
+- def mocked_urlopen_fail(self, monkeypatch: MonkeyPatch):
+- """Monkeypatch the actual urlopen call to emulate a HTTP Error 400."""
+- calls = []
+-
+- import urllib.error
+- import urllib.request
+-
+- def mocked(url, data):
+- calls.append((url, data))
+- raise urllib.error.HTTPError(
+- url, 400, "Bad request", email.message.Message(), io.BytesIO()
+- )
+-
+- monkeypatch.setattr(urllib.request, "urlopen", mocked)
+- return calls
+-
+ @pytest.fixture
+ def mocked_urlopen_invalid(self, monkeypatch: MonkeyPatch):
+ """Monkeypatch the actual urlopen calls done by the internal plugin
+@@ -158,10 +142,33 @@ class TestPaste:
+ )
+ assert len(mocked_urlopen_invalid) == 1
+
+- def test_pastebin_http_error(self, pastebin, mocked_urlopen_fail) -> None:
+- result = pastebin.create_new_paste(b"full-paste-contents")
++ def test_pastebin_http_error(self, pastebin) -> None:
++ import urllib.error
++
++ with mock.patch(
++ "urllib.request.urlopen",
++ side_effect=urllib.error.HTTPError(
++ url="https://bpa.st",
++ code=400,
++ msg="Bad request",
++ hdrs=email.message.Message(),
++ fp=io.BytesIO(),
++ ),
++ ) as mock_urlopen:
++ result = pastebin.create_new_paste(b"full-paste-contents")
+ assert result == "bad response: HTTP Error 400: Bad request"
+- assert len(mocked_urlopen_fail) == 1
++ assert len(mock_urlopen.mock_calls) == 1
++
++ def test_pastebin_url_error(self, pastebin) -> None:
++ import urllib.error
++
++ with mock.patch(
++ "urllib.request.urlopen",
++ side_effect=urllib.error.URLError("the url was bad"),
++ ) as mock_urlopen:
++ result = pastebin.create_new_paste(b"full-paste-contents")
++ assert result == "bad response: "
++ assert len(mock_urlopen.mock_calls) == 1
+
+ def test_create_new_paste(self, pastebin, mocked_urlopen) -> None:
+ result = pastebin.create_new_paste(b"full-paste-contents")
+
+From be1a0f48a6b604039799470bd3986b20a519faa8 Mon Sep 17 00:00:00 2001
+From: Thomas Grainger
+Date: Fri, 30 May 2025 22:11:01 +0100
+Subject: [PATCH 19/19] Update .github/workflows/test.yml
+
+---
+ .github/workflows/test.yml | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
+index 9354ddd..8547a4c 100644
+--- a/.github/workflows/test.yml
++++ b/.github/workflows/test.yml
+@@ -236,7 +236,7 @@ jobs:
+ uses: actions/setup-python@v5
+ with:
+ python-version: ${{ matrix.python }}
+- check-latest: ${{ endsWith(matrix.python, '-dev') }}
++ check-latest: true
+ allow-prereleases: true
+
+ - name: Install dependencies
diff --git a/13502.patch b/13502.patch
new file mode 100644
index 0000000..ec4bed1
--- /dev/null
+++ b/13502.patch
@@ -0,0 +1,306 @@
+From d22f91b24b724bbf6011caf770b9611cf33789c8 Mon Sep 17 00:00:00 2001
+From: Bruno Oliveira
+Date: Mon, 9 Jun 2025 19:22:40 -0300
+Subject: [PATCH] Fix compatibility with Twisted 25
+
+As discussed in https://github.com/pytest-dev/pytest/pull/13502, the fix for compatibility with Twisted 25+ is simpler. Therefore, it makes sense to implement both fixes (for Twisted 24 and Twisted 25) in parallel. This way, we can eventually drop support for Twisted <25 and keep only the simpler workaround.
+
+In addition, the `unittestextras` tox environment has been replaced with dedicated test environments for `asynctest`, `Twisted 24`, and `Twisted 25`.
+
+Fixes #13497
+---
+ changelog/13497.bugfix.rst | 1 +
+ src/_pytest/unittest.py | 187 ++++++++++++++++++++++++++-----------
+ tox.ini | 17 +++-
+ 3 files changed, 148 insertions(+), 57 deletions(-)
+ create mode 100644 changelog/13497.bugfix.rst
+
+diff --git a/changelog/13497.bugfix.rst b/changelog/13497.bugfix.rst
+new file mode 100644
+index 0000000..75b4996
+--- /dev/null
++++ b/changelog/13497.bugfix.rst
+@@ -0,0 +1 @@
++Fixed compatibility with ``Twisted 25+``.
+diff --git a/src/_pytest/unittest.py b/src/_pytest/unittest.py
+index 8cecd4f..ef6ef64 100644
+--- a/src/_pytest/unittest.py
++++ b/src/_pytest/unittest.py
+@@ -3,16 +3,16 @@
+
+ from __future__ import annotations
+
++from collections.abc import Callable
++from collections.abc import Generator
++from collections.abc import Iterable
++from collections.abc import Iterator
++from enum import auto
++from enum import Enum
+ import inspect
+ import sys
+ import traceback
+ import types
+-from typing import Any
+-from typing import Callable
+-from typing import Generator
+-from typing import Iterable
+-from typing import Tuple
+-from typing import Type
+ from typing import TYPE_CHECKING
+ from typing import Union
+
+@@ -20,6 +20,7 @@ import _pytest._code
+ from _pytest.compat import is_async_function
+ from _pytest.config import hookimpl
+ from _pytest.fixtures import FixtureRequest
++from _pytest.monkeypatch import MonkeyPatch
+ from _pytest.nodes import Collector
+ from _pytest.nodes import Item
+ from _pytest.outcomes import exit
+@@ -43,8 +44,8 @@ if TYPE_CHECKING:
+
+
+ _SysExcInfoType = Union[
+- Tuple[Type[BaseException], BaseException, types.TracebackType],
+- Tuple[None, None, None],
++ tuple[type[BaseException], BaseException, types.TracebackType],
++ tuple[None, None, None],
+ ]
+
+
+@@ -230,8 +231,7 @@ class TestCaseFunction(Function):
+ pass
+
+ def _addexcinfo(self, rawexcinfo: _SysExcInfoType) -> None:
+- # Unwrap potential exception info (see twisted trial support below).
+- rawexcinfo = getattr(rawexcinfo, "_rawexcinfo", rawexcinfo)
++ rawexcinfo = _handle_twisted_exc_info(rawexcinfo)
+ try:
+ excinfo = _pytest._code.ExceptionInfo[BaseException].from_exc_info(
+ rawexcinfo # type: ignore[arg-type]
+@@ -387,49 +387,130 @@ def pytest_runtest_makereport(item: Item, call: CallInfo[None]) -> None:
+ call.excinfo = call2.excinfo
+
+
+-# Twisted trial support.
+-classImplements_has_run = False
+-
+-
+-@hookimpl(wrapper=True)
+-def pytest_runtest_protocol(item: Item) -> Generator[None, object, object]:
+- if isinstance(item, TestCaseFunction) and "twisted.trial.unittest" in sys.modules:
+- ut: Any = sys.modules["twisted.python.failure"]
+- global classImplements_has_run
+- Failure__init__ = ut.Failure.__init__
+- if not classImplements_has_run:
+- from twisted.trial.itrial import IReporter
+- from zope.interface import classImplements
+-
+- classImplements(TestCaseFunction, IReporter)
+- classImplements_has_run = True
+-
+- def excstore(
+- self, exc_value=None, exc_type=None, exc_tb=None, captureVars=None
+- ):
+- if exc_value is None:
+- self._rawexcinfo = sys.exc_info()
+- else:
+- if exc_type is None:
+- exc_type = type(exc_value)
+- self._rawexcinfo = (exc_type, exc_value, exc_tb)
+- try:
+- Failure__init__(
+- self, exc_value, exc_type, exc_tb, captureVars=captureVars
+- )
+- except TypeError:
+- Failure__init__(self, exc_value, exc_type, exc_tb)
+-
+- ut.Failure.__init__ = excstore
+- try:
+- res = yield
+- finally:
+- ut.Failure.__init__ = Failure__init__
+- else:
+- res = yield
+- return res
+-
+-
+ def _is_skipped(obj) -> bool:
+ """Return True if the given object has been marked with @unittest.skip."""
+ return bool(getattr(obj, "__unittest_skip__", False))
++
++
++def pytest_configure() -> None:
++ """Register the TestCaseFunction class as an IReporter if twisted.trial is available."""
++ if _get_twisted_version() is not TwistedVersion.NotInstalled:
++ from twisted.trial.itrial import IReporter
++ from zope.interface import classImplements
++
++ classImplements(TestCaseFunction, IReporter)
++
++
++class TwistedVersion(Enum):
++ """
++ The Twisted version installed in the environment.
++
++ We have different workarounds in place for different versions of Twisted.
++ """
++
++ # Twisted version 24 or prior.
++ Version24 = auto()
++ # Twisted version 25 or later.
++ Version25 = auto()
++ # Twisted version is not available.
++ NotInstalled = auto()
++
++
++def _get_twisted_version() -> TwistedVersion:
++ # We need to check if "twisted.trial.unittest" is specifically present in sys.modules.
++ # This is because we intend to integrate with Trial only when it's actively running
++ # the test suite, but not needed when only other Twisted components are in use.
++ if "twisted.trial.unittest" not in sys.modules:
++ return TwistedVersion.NotInstalled
++
++ import importlib.metadata
++
++ import packaging.version
++
++ version_str = importlib.metadata.version("twisted")
++ version = packaging.version.parse(version_str)
++ if version.major <= 24:
++ return TwistedVersion.Version24
++ else:
++ return TwistedVersion.Version25
++
++
++# Name of the attribute in `twisted.python.Failure` instances that stores
++# the `sys.exc_info()` tuple.
++# See twisted.trial support in `pytest_runtest_protocol`.
++TWISTED_RAW_EXCINFO_ATTR = "_twisted_raw_excinfo"
++
++
++@hookimpl(wrapper=True)
++def pytest_runtest_protocol(item: Item) -> Iterator[None]:
++ if _get_twisted_version() is TwistedVersion.Version24:
++ import twisted.python.failure as ut
++
++ # Monkeypatch `Failure.__init__` to store the raw exception info.
++ original__init__ = ut.Failure.__init__
++
++ def store_raw_exception_info(
++ self, exc_value=None, exc_type=None, exc_tb=None, captureVars=None
++ ): # pragma: no cover
++ if exc_value is None:
++ raw_exc_info = sys.exc_info()
++ else:
++ if exc_type is None:
++ exc_type = type(exc_value)
++ if exc_tb is None:
++ exc_tb = sys.exc_info()[2]
++ raw_exc_info = (exc_type, exc_value, exc_tb)
++ setattr(self, TWISTED_RAW_EXCINFO_ATTR, tuple(raw_exc_info))
++ try:
++ original__init__(
++ self, exc_value, exc_type, exc_tb, captureVars=captureVars
++ )
++ except TypeError: # pragma: no cover
++ original__init__(self, exc_value, exc_type, exc_tb)
++
++ with MonkeyPatch.context() as patcher:
++ patcher.setattr(ut.Failure, "__init__", store_raw_exception_info)
++ return (yield)
++ else:
++ return (yield)
++
++
++def _handle_twisted_exc_info(
++ rawexcinfo: _SysExcInfoType | BaseException,
++) -> _SysExcInfoType:
++ """
++ Twisted passes a custom Failure instance to `addError()` instead of using `sys.exc_info()`.
++ Therefore, if `rawexcinfo` is a `Failure` instance, convert it into the equivalent `sys.exc_info()` tuple
++ as expected by pytest.
++ """
++ twisted_version = _get_twisted_version()
++ if twisted_version is TwistedVersion.NotInstalled:
++ # Unfortunately, because we cannot import `twisted.python.failure` at the top of the file
++ # and use it in the signature, we need to use `type:ignore` here because we cannot narrow
++ # the type properly in the `if` statement above.
++ return rawexcinfo # type:ignore[return-value]
++ elif twisted_version is TwistedVersion.Version24:
++ # Twisted calls addError() passing its own classes (like `twisted.python.Failure`), which violates
++ # the `addError()` signature, so we extract the original `sys.exc_info()` tuple which is stored
++ # in the object.
++ if hasattr(rawexcinfo, TWISTED_RAW_EXCINFO_ATTR):
++ saved_exc_info = getattr(rawexcinfo, TWISTED_RAW_EXCINFO_ATTR)
++ # Delete the attribute from the original object to avoid leaks.
++ delattr(rawexcinfo, TWISTED_RAW_EXCINFO_ATTR)
++ return saved_exc_info # type:ignore[no-any-return]
++ return rawexcinfo # type:ignore[return-value]
++ elif twisted_version is TwistedVersion.Version25:
++ if isinstance(rawexcinfo, BaseException):
++ import twisted.python.failure
++
++ if isinstance(rawexcinfo, twisted.python.failure.Failure):
++ tb = rawexcinfo.__traceback__
++ if tb is None:
++ tb = sys.exc_info()[2]
++ return type(rawexcinfo.value), rawexcinfo.value, tb
++
++ return rawexcinfo # type:ignore[return-value]
++ else:
++ # Ideally we would use assert_never() here, but it is not available in all Python versions
++ # we support, plus we do not require `type_extensions` currently.
++ assert False, f"Unexpected Twisted version: {twisted_version}"
+diff --git a/tox.ini b/tox.ini
+index 6f49b80..ac47f6f 100644
+--- a/tox.ini
++++ b/tox.ini
+@@ -37,7 +37,9 @@ description =
+ pexpect: against `pexpect`
+ pluggymain: against the bleeding edge `pluggy` from Git
+ pylib: against `py` lib
+- unittestextras: against the unit test extras
++ twisted24: against the unit test extras with twisted prior to 24.0
++ twisted25: against the unit test extras with twisted 25.0 or later
++ asynctest: against the unit test extras with asynctest
+ xdist: with pytest in parallel mode
+ under `{basepython}`
+ doctesting: including doctests
+@@ -52,7 +54,7 @@ passenv =
+ TERM
+ SETUPTOOLS_SCM_PRETEND_VERSION_FOR_PYTEST
+ setenv =
+- _PYTEST_TOX_DEFAULT_POSARGS={env:_PYTEST_TOX_POSARGS_DOCTESTING:} {env:_PYTEST_TOX_POSARGS_LSOF:} {env:_PYTEST_TOX_POSARGS_XDIST:}
++ _PYTEST_TOX_DEFAULT_POSARGS={env:_PYTEST_TOX_POSARGS_DOCTESTING:} {env:_PYTEST_TOX_POSARGS_LSOF:} {env:_PYTEST_TOX_POSARGS_XDIST:} {env:_PYTEST_FILES:}
+
+ # See https://docs.python.org/3/library/io.html#io-encoding-warning
+ # If we don't enable this, neither can any of our downstream users!
+@@ -67,6 +69,12 @@ setenv =
+
+ doctesting: _PYTEST_TOX_POSARGS_DOCTESTING=doc/en
+
++ # The configurations below are related only to standard unittest support.
++ # Run only tests from test_unittest.py.
++ asynctest: _PYTEST_FILES=testing/test_unittest.py
++ twisted24: _PYTEST_FILES=testing/test_unittest.py
++ twisted25: _PYTEST_FILES=testing/test_unittest.py
++
+ nobyte: PYTHONDONTWRITEBYTECODE=1
+
+ lsof: _PYTEST_TOX_POSARGS_LSOF=--lsof
+@@ -80,8 +88,9 @@ deps =
+ pexpect: pexpect>=4.8.0
+ pluggymain: pluggy @ git+https://github.com/pytest-dev/pluggy.git
+ pylib: py>=1.8.2
+- unittestextras: twisted
+- unittestextras: asynctest
++ twisted24: twisted<25
++ twisted25: twisted>=25
++ asynctest: asynctest
+ xdist: pytest-xdist>=2.1.0
+ xdist: -e .
+ {env:_PYTEST_TOX_EXTRA_DEP:}
+--
+2.50.1
+
diff --git a/13548.patch b/13548.patch
new file mode 100644
index 0000000..9b18a1b
--- /dev/null
+++ b/13548.patch
@@ -0,0 +1,120 @@
+From 09bb9a1354310c366052b92e907690f89a8aa2b4 Mon Sep 17 00:00:00 2001
+From: Ben Gartner
+Date: Fri, 20 Jun 2025 20:45:13 -0500
+Subject: [PATCH 1/5] Fix test_doctest_unexpected_exception
+
+---
+ testing/test_doctest.py | 5 ++---
+ 1 file changed, 2 insertions(+), 3 deletions(-)
+
+diff --git a/testing/test_doctest.py b/testing/test_doctest.py
+index 1a852ebc82a..49b6a4e9012 100644
+--- a/testing/test_doctest.py
++++ b/testing/test_doctest.py
+@@ -223,9 +223,8 @@ def test_doctest_unexpected_exception(self, pytester: Pytester):
+ "002 >>> 0 / i",
+ "UNEXPECTED EXCEPTION: ZeroDivisionError*",
+ "Traceback (most recent call last):",
+- ' File "*/doctest.py", line *, in __run',
+- " *",
+- *((" *^^^^*", " *", " *") if sys.version_info >= (3, 13) else ()),
++ *((' File "*/doctest.py", line *, in __run', " *") if sys.version_info <= (3, 14) else ()),
++ *((" *^^^^*", " *", " *") if sys.version_info[:2] == (3, 13) else ()),
+ ' File "", line 1, in ',
+ "ZeroDivisionError: division by zero",
+ "*/test_doctest_unexpected_exception.txt:2: UnexpectedException",
+
+From deb49db0af701e4eeeae2fb06a6c2afa3cc493c0 Mon Sep 17 00:00:00 2001
+From: Ben Gartner
+Date: Fri, 20 Jun 2025 21:42:00 -0500
+Subject: [PATCH 2/5] Bugfix message
+
+---
+ changelog/13547.bugfix.rst | 1 +
+ 1 file changed, 1 insertion(+)
+ create mode 100644 changelog/13547.bugfix.rst
+
+diff --git a/changelog/13547.bugfix.rst b/changelog/13547.bugfix.rst
+new file mode 100644
+index 00000000000..3aa0e3671db
+--- /dev/null
++++ b/changelog/13547.bugfix.rst
+@@ -0,0 +1 @@
++Corrected expected message for test_doctest_unexpected_exception in Python 3.14
+\ No newline at end of file
+
+From 358da327c8c0b78840344e055202dce14529d1d8 Mon Sep 17 00:00:00 2001
+From: "pre-commit-ci[bot]"
+ <66853113+pre-commit-ci[bot]@users.noreply.github.com>
+Date: Sat, 21 Jun 2025 02:43:23 +0000
+Subject: [PATCH 3/5] [pre-commit.ci] auto fixes from pre-commit.com hooks
+
+for more information, see https://pre-commit.ci
+---
+ testing/test_doctest.py | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/testing/test_doctest.py b/testing/test_doctest.py
+index 49b6a4e9012..f4ed976c839 100644
+--- a/testing/test_doctest.py
++++ b/testing/test_doctest.py
+@@ -223,7 +223,11 @@ def test_doctest_unexpected_exception(self, pytester: Pytester):
+ "002 >>> 0 / i",
+ "UNEXPECTED EXCEPTION: ZeroDivisionError*",
+ "Traceback (most recent call last):",
+- *((' File "*/doctest.py", line *, in __run', " *") if sys.version_info <= (3, 14) else ()),
++ *(
++ (' File "*/doctest.py", line *, in __run', " *")
++ if sys.version_info <= (3, 14)
++ else ()
++ ),
+ *((" *^^^^*", " *", " *") if sys.version_info[:2] == (3, 13) else ()),
+ ' File "", line 1, in ',
+ "ZeroDivisionError: division by zero",
+
+From e851833a4875d2705284b2ebcb576c9b3a4a4c29 Mon Sep 17 00:00:00 2001
+From: "pre-commit-ci[bot]"
+ <66853113+pre-commit-ci[bot]@users.noreply.github.com>
+Date: Sat, 21 Jun 2025 02:43:43 +0000
+Subject: [PATCH 4/5] [pre-commit.ci] auto fixes from pre-commit.com hooks
+
+for more information, see https://pre-commit.ci
+---
+ changelog/13547.bugfix.rst | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+diff --git a/changelog/13547.bugfix.rst b/changelog/13547.bugfix.rst
+index 3aa0e3671db..84db9d627ce 100644
+--- a/changelog/13547.bugfix.rst
++++ b/changelog/13547.bugfix.rst
+@@ -1 +1 @@
+-Corrected expected message for test_doctest_unexpected_exception in Python 3.14
+\ No newline at end of file
++Corrected expected message for test_doctest_unexpected_exception in Python 3.14
+
+From 6975dd475f745c701c234918854019dbe1d1fef1 Mon Sep 17 00:00:00 2001
+From: Bruno Oliveira
+Date: Sun, 22 Jun 2025 12:09:46 -0300
+Subject: [PATCH 5/5] Update and rename 13547.bugfix.rst to 13547.contrib.rst
+
+---
+ changelog/13547.bugfix.rst | 1 -
+ changelog/13547.contrib.rst | 1 +
+ 2 files changed, 1 insertion(+), 1 deletion(-)
+ delete mode 100644 changelog/13547.bugfix.rst
+ create mode 100644 changelog/13547.contrib.rst
+
+diff --git a/changelog/13547.bugfix.rst b/changelog/13547.bugfix.rst
+deleted file mode 100644
+index 84db9d627ce..00000000000
+--- a/changelog/13547.bugfix.rst
++++ /dev/null
+@@ -1 +0,0 @@
+-Corrected expected message for test_doctest_unexpected_exception in Python 3.14
+diff --git a/changelog/13547.contrib.rst b/changelog/13547.contrib.rst
+new file mode 100644
+index 00000000000..d8a240c0506
+--- /dev/null
++++ b/changelog/13547.contrib.rst
+@@ -0,0 +1 @@
++Self-testing: corrected expected message for ``test_doctest_unexpected_exception`` in Python ``3.14``.
diff --git a/changelog b/changelog
new file mode 100644
index 0000000..a63b473
--- /dev/null
+++ b/changelog
@@ -0,0 +1,527 @@
+* Fri Jan 26 2024 Fedora Release Engineering - 7.4.3-3
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild
+
+* Sun Jan 21 2024 Fedora Release Engineering - 7.4.3-2
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_40_Mass_Rebuild
+
+* Thu Nov 09 2023 Miro Hrončok - 7.4.3-1
+- Update to 7.4.3
+- Changelog: https://docs.pytest.org/en/stable/changelog.html#pytest-7-4-3-2023-10-24
+- Fixes: rhbz#2245983
+
+* Fri Sep 08 2023 Miro Hrončok - 7.4.2-1
+- Update to 7.4.2
+- Changelog: https://docs.pytest.org/en/stable/changelog.html#pytest-7-4-2-2023-09-07
+- Fixes: rhbz#2237942
+
+* Wed Sep 06 2023 Miro Hrončok - 7.4.1-1
+- Update to 7.4.1
+- Changelog: https://docs.pytest.org/en/stable/changelog.html#pytest-7-4-1-2023-09-02
+- Fixes: rhbz#2236995
+
+* Mon Aug 07 2023 Lumír Balhar - 7.4.0-1
+- Update to 7.4.0
+Resolves: rhbz#2216956
+
+* Fri Jul 21 2023 Fedora Release Engineering - 7.3.2-4
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_39_Mass_Rebuild
+
+* Thu Jun 29 2023 Python Maint - 7.3.2-3
+- Rebuilt for Python 3.12
+
+* Tue Jun 13 2023 Python Maint - 7.3.2-2
+- Bootstrap for Python 3.12
+
+* Mon Jun 12 2023 Maxwell G - 7.3.2-1
+- Update to 7.3.2. Fixes rhbz#2213992.
+
+* Mon Apr 24 2023 Miro Hrončok - 7.3.1-2
+- Fix build with setuptools >= 67.5.0
+- Fixes: rhbz#2188982
+
+* Mon Apr 17 2023 Miro Hrončok - 7.3.1-1
+- Update to 7.3.1
+- Changelog: https://docs.pytest.org/en/stable/changelog.html#pytest-7-3-1-2023-04-14
+- Fixes: rhbz#2186895
+
+* Sun Apr 09 2023 Miro Hrončok - 7.3.0-1
+- Update to 7.3.0
+- Changelog: https://docs.pytest.org/en/stable/changelog.html#pytest-7-3-0-2023-04-08
+- Fixes: rhbz#2185393
+
+* Fri Mar 24 2023 Miro Hrončok - 7.2.2-1
+- Update to 7.2.2
+- Changelog: https://docs.pytest.org/en/7.2.x/changelog.html#pytest-7-2-2-2023-03-03
+- Fixes: rhbz#2175310
+
+* Fri Feb 10 2023 Stephen Gallagher - 7.2.1-2
+- Don't build tests and docs on RHEL to reduce dependencies
+
+* Fri Jan 27 2023 Miro Hrončok - 7.2.1-1
+- Update to 7.2.1
+- Fixes: rhbz#2160925
+
+* Fri Jan 20 2023 Fedora Release Engineering - 7.2.0-3
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_38_Mass_Rebuild
+
+* Sat Dec 10 2022 Miro Hrončok - 7.2.0-2
+- Remove -s from Python shebang,
+ ensure that packages installed with pip to user locations are testable
+- Fixes: rhbz#2152171
+
+* Tue Nov 01 2022 Lumír Balhar - 7.2.0-1
+- Update to 7.2.0
+Resolves: rhbz#2137514
+
+* Sat Sep 3 2022 Thomas Moschny - 7.1.3-1
+- Update to 7.1.3
+- Fixes: rhbz#2123701
+
+* Fri Jul 22 2022 Fedora Release Engineering - 7.1.2-5
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_37_Mass_Rebuild
+
+* Wed Jul 13 2022 Miro Hrončok - 7.1.2-4
+- Adjust tests for a last minute Python 3.11 change in the traceback format
+
+* Tue Jun 14 2022 Python Maint - 7.1.2-3
+- Rebuilt for Python 3.11
+
+* Mon Jun 13 2022 Python Maint - 7.1.2-2
+- Bootstrap for Python 3.11
+
+* Fri Apr 08 2022 Lumír Balhar - 7.1.2-1
+- Update to 7.1.2
+Resolves: rhbz#2063549
+
+* Tue Mar 01 2022 Miro Hrončok - 7.0.1-1
+- Update to 7.0.1
+- Fixes: rhbz#2050629
+
+* Fri Jan 21 2022 Miro Hrončok - 7.0.0~rc1-1
+- Update to 7.0.0rc1
+- Fixes: rhbz#2029764
+
+* Fri Jan 21 2022 Fedora Release Engineering - 6.2.5-2
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_36_Mass_Rebuild
+
+* Wed Sep 15 2021 Charalampos Stratakis - 6.2.5-1
+- Update to 6.2.5
+- Fixes: rhbz#1999270
+
+* Fri Aug 27 2021 Miro Hrončok - 6.2.4-7
+- Enable all tests during package build
+
+* Fri Aug 27 2021 Miro Hrončok - 6.2.4-6
+- Allow pluggy >=1.0
+
+* Fri Jul 23 2021 Fedora Release Engineering - 6.2.4-5
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_35_Mass_Rebuild
+
+* Mon Jul 12 2021 Miro Hrončok - 6.2.4-4
+- Adjust pytest's own tests for changes in Python 3.10.0b4
+
+* Fri Jun 04 2021 Python Maint - 6.2.4-3
+- Rebuilt for Python 3.10
+
+* Wed Jun 02 2021 Python Maint - 6.2.4-2
+- Bootstrap for Python 3.10
+
+* Tue May 04 2021 Miro Hrončok - 6.2.4-1
+- Update to 6.2.4
+- Fixes: rhbz#1956942
+
+* Mon Apr 12 2021 Miro Hrončok - 6.2.3-1
+- Update to 6.2.3
+- Fixes: rhbz#1946061
+
+* Wed Mar 10 2021 Miro Hrončok - 6.2.2-2
+- Drop redundant build dependency on wcwidth (unused since 6.0.0rc1)
+
+* Wed Jan 27 2021 Miro Hrončok - 6.2.2-1
+- Update to 6.2.2
+- Update the description
+- Fixes: rhbz#1882935
+
+* Wed Jan 27 2021 Fedora Release Engineering - 6.0.2-3
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_34_Mass_Rebuild
+
+* Wed Jan 20 2021 Miro Hrončok - 6.0.2-2
+- Workaround the bracketed-paste mode breaking tests with Bash 5.1+
+
+* Sat Sep 12 2020 Thomas Moschny - 6.0.2-1
+- Update to 6.0.2.
+
+* Thu Aug 06 2020 Miro Hrončok - 6.0.1-1
+- Update to 6.0.1 (#1862097)
+
+* Tue Jul 28 2020 Miro Hrončok - 6.0.0~rc1-1
+- Update to 6.0.0rc1
+
+* Tue Jul 28 2020 Fedora Release Engineering - 5.4.3-2
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_33_Mass_Rebuild
+
+* Fri Jun 5 2020 Thomas Moschny - 5.4.3-1
+- Update to 5.4.3.
+
+* Fri May 29 2020 Miro Hrončok - 5.4.2-1
+- Update to 5.4.2 (#1707986)
+
+* Sun May 24 2020 Miro Hrončok - 4.6.10-3
+- Rebuilt for Python 3.9
+
+* Fri May 22 2020 Miro Hrončok - 4.6.10-2
+- Bootstrap for Python 3.9
+
+* Fri May 08 2020 Miro Hrončok - 4.6.10-1
+- Update to 4.6.10.
+
+* Thu Jan 30 2020 Fedora Release Engineering - 4.6.9-2
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_32_Mass_Rebuild
+
+* Sun Jan 5 2020 Thomas Moschny - 4.6.9-1
+- Update to 4.6.9.
+
+* Fri Jan 3 2020 Thomas Moschny - 4.6.8-1
+- Update to 4.6.8.
+
+* Fri Dec 06 2019 Miro Hrončok - 4.6.7-1
+- Update to 4.6.7
+
+* Fri Oct 25 2019 Thomas Moschny - 4.6.6-1
+- Update to 4.6.6.
+
+* Thu Oct 03 2019 Miro Hrončok - 4.6.5-4
+- Rebuilt for Python 3.8.0rc1 (#1748018)
+
+* Sat Aug 17 2019 Miro Hrončok - 4.6.5-3
+- Rebuilt for Python 3.8
+
+* Thu Aug 15 2019 Miro Hrončok - 4.6.5-2
+- Bootstrap for Python 3.8
+
+* Wed Aug 14 2019 Thomas Moschny - 4.6.5-1
+- Update to 4.6.5.
+- Add missing BR on make.
+
+* Fri Jul 26 2019 Fedora Release Engineering - 4.6.4-3
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_31_Mass_Rebuild
+
+* Tue Jul 23 2019 Miro Hrončok - 4.6.4-2
+- Fix a bad conflict
+
+* Mon Jul 01 2019 Miro Hrončok - 4.6.4-1
+- Update to 4.6.4, move python2-pytest to its own source package
+- Make /usr/bin/pytest and /usr/bin/py.test Python 3
+
+* Fri Jun 21 2019 Petr Viktorin - 4.4.1-2
+- Remove optional test dependencies for Python 2 entirely
+
+* Tue Apr 16 2019 Thomas Moschny - 4.4.1-1
+- Update to 4.4.1 (see PR#9).
+- Remove test dependencies on python2-hypothesis and python2-twisted (see PR#10).
+
+* Sat Mar 16 2019 Miro Hrončok - 4.3.1-1
+- Update to 4.3.1
+
+* Tue Mar 12 2019 Miro Hrončok - 4.3.0-1
+- Update to 4.3.0 and fix FTBFS (#1671167, #1687384)
+
+* Mon Feb 18 2019 Igor Gnatenko - 3.9.3-3
+- Enable python dependency generator
+
+* Sat Feb 02 2019 Fedora Release Engineering - 3.9.3-2
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_30_Mass_Rebuild
+
+* Wed Oct 31 2018 Thomas Moschny - 3.9.3-1
+- Update to 3.9.3.
+
+* Tue Oct 23 2018 Thomas Moschny - 3.9.2-1
+- Update to 3.9.2.
+
+* Wed Oct 17 2018 Thomas Moschny - 3.9.1-1
+- Update to 3.9.1.
+
+* Tue Oct 16 2018 Thomas Moschny - 3.8.2-3
+- Add python2-pathlib2 runtime requirement (rhbz#1639718).
+
+* Tue Oct 16 2018 Nils Philippsen - 3.8.2-2
+- versionize pluggy dependencies
+
+* Tue Oct 16 2018 Thomas Moschny - 3.8.2-1
+- Update to 3.8.2.
+
+* Sat Sep 29 2018 Thomas Moschny - 3.6.4-1
+- Update to 3.6.4.
+
+* Fri Jul 13 2018 Fedora Release Engineering - 3.6.3-2
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_29_Mass_Rebuild
+
+* Thu Jul 5 2018 Thomas Moschny - 3.6.3-1
+- Update to 3.6.3.
+
+* Mon Jul 02 2018 Miro Hrončok - 3.6.2-3
+- Enable timeout
+
+* Mon Jul 02 2018 Miro Hrončok - 3.6.2-2
+- Rebuilt for Python 3.7 (without timeout)
+
+* Thu Jun 28 2018 Thomas Moschny - 3.6.2-1
+- Update to 3.6.2.
+
+* Mon Jun 18 2018 Miro Hrončok - 3.6.1-3
+- Rebuilt for Python 3.7
+
+* Thu Jun 14 2018 Miro Hrončok - 3.6.1-2
+- Bootstrap for Python 3.7
+
+* Tue Jun 5 2018 Thomas Moschny - 3.6.1-1
+- Update to 3.6.1.
+
+* Mon May 28 2018 Miro Hrončok - 3.6.0-1
+- Update to 3.6.0 (#1581692)
+- Require and BuildRequire atomicwrites
+
+* Sat May 19 2018 Thomas Moschny - 3.5.1-1
+- Update to 3.5.1.
+- Build the documentation with Python3.
+- Update requirements.
+
+* Thu Mar 15 2018 Zbigniew Jędrzejewski-Szmek - 3.4.2-2
+- Add Requires for required modules
+
+* Wed Mar 14 2018 Charalampos Stratakis - 3.4.2-1
+- Update to 3.4.2
+
+* Fri Feb 09 2018 Fedora Release Engineering - 3.2.3-4
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild
+
+* Tue Nov 07 2017 Igor Gnatenko - 3.2.3-3
+- Use better Obsoletes for platform-python
+
+* Fri Nov 03 2017 Igor Gnatenko - 3.2.3-2
+- Remove platform-python subpackage
+- Cleanup conditionals
+
+* Sat Oct 7 2017 Thomas Moschny - 3.2.3-1
+- Update to 3.2.3.
+
+* Sat Sep 9 2017 Thomas Moschny - 3.2.2-1
+- Update to 3.2.2.
+- Move BRs to their respective subpackages.
+- Enable the platform-python subpackage only on F27+.
+
+* Thu Aug 24 2017 Miro Hrončok - 3.2.1-3
+- Rebuilt for rhbz#1484607
+
+* Fri Aug 11 2017 Petr Viktorin - 3.2.1-2
+- Add subpackage for platform-python (https://fedoraproject.org/wiki/Changes/Platform_Python_Stack)
+
+* Wed Aug 9 2017 Thomas Moschny - 3.2.1-1
+- Update to 3.2.1.
+
+* Wed Aug 02 2017 Gwyn Ciesla - 3.2.0-1
+- 3.2.0.
+
+* Sun Jul 30 2017 Thomas Moschny - 3.1.3-1
+- Update to 3.1.3.
+- Update BRs.
+
+* Thu Jul 27 2017 Fedora Release Engineering - 3.1.1-2
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_27_Mass_Rebuild
+
+* Sat Jun 3 2017 Thomas Moschny - 3.1.1-1
+- Update to 3.1.1.
+- Add BR on setuptools_scm.
+
+* Wed Mar 15 2017 Thomas Moschny - 3.0.7-1
+- Update to 3.0.7.
+
+* Sat Feb 11 2017 Fedora Release Engineering - 3.0.6-2
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_26_Mass_Rebuild
+
+* Sun Jan 29 2017 Thomas Moschny - 3.0.6-1
+- Update to 3.0.6.
+- Drop patch applied upstream.
+
+* Tue Dec 13 2016 Miro Hrončok - 3.0.5-2
+- Rebuild for Python 3.6
+
+* Tue Dec 6 2016 Thomas Moschny - 3.0.5-1
+- Update to 3.0.5.
+
+* Mon Nov 28 2016 Thomas Moschny - 3.0.4-1
+- Update to 3.0.4.
+
+* Fri Sep 30 2016 Thomas Moschny - 3.0.3-1
+- Update to 3.0.3.
+- Update requirements.
+
+* Tue Jul 19 2016 Fedora Release Engineering - 2.9.2-2
+- https://fedoraproject.org/wiki/Changes/Automatic_Provides_for_Python_RPM_Packages
+
+* Fri Jun 3 2016 Thomas Moschny - 2.9.2-1
+- Update to 2.9.2.
+
+* Tue May 31 2016 Nils Philippsen
+- fix source URL
+
+* Sat Apr 9 2016 Thomas Moschny - 2.9.1-1
+- Update to 2.9.1.
+- Packaging updates.
+
+* Tue Feb 2 2016 Orion Poplawski - 2.8.7-2
+- Use new python macros
+- Fix python3 package file ownership
+
+* Sun Jan 24 2016 Thomas Moschny - 2.8.7-1
+- Update to 2.8.7.
+
+* Fri Jan 22 2016 Thomas Moschny - 2.8.6-1
+- Update to 2.8.6.
+
+* Wed Dec 30 2015 Orion Poplawski - 2.8.5-1
+- Update to 2.8.5
+
+* Wed Dec 30 2015 Orion Poplawski - 2.8.2-3
+- Re-enable pexpect in tests
+
+* Wed Nov 11 2015 Fedora Release Engineering - 2.8.2-2
+- Rebuilt for https://fedoraproject.org/wiki/Changes/python3.5
+
+* Tue Oct 20 2015 Thomas Moschny - 2.8.2-1
+- Update to 2.8.2.
+
+* Mon Oct 12 2015 Robert Kuska - 2.7.3-2
+- Rebuilt for Python3.5 rebuild
+
+* Thu Sep 17 2015 Thomas Moschny - 2.7.3-1
+- Update to 2.7.3.
+- Provide additional symlinks to the pytest executables (rhbz#1249891).
+
+* Mon Sep 14 2015 Orion Poplawski - 2.7.2-2
+- Provide python2-pytest, use python_provide macro
+
+* Thu Jun 25 2015 Thomas Moschny - 2.7.2-1
+- Update to 2.7.2.
+- Small fixes.
+
+* Thu Jun 18 2015 Fedora Release Engineering - 2.7.1-2
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_23_Mass_Rebuild
+
+* Sat May 23 2015 Thomas Moschny - 2.7.1-1
+- Update to 2.7.1.
+
+* Mon Apr 20 2015 Thomas Moschny - 2.7.0-1
+- Update to 2.7.0.
+- Apply updated Python packaging guidelines.
+- Mark LICENSE with %%license.
+
+* Tue Dec 2 2014 Thomas Moschny - 2.6.4-1
+- Update to 2.6.4.
+
+* Sat Oct 11 2014 Thomas Moschny - 2.6.3-1
+- Update to 2.6.3.
+
+* Fri Aug 8 2014 Thomas Moschny - 2.6.1-1
+- Update to 2.6.1.
+
+* Fri Aug 1 2014 Thomas Moschny - 2.6.0-1
+- Update to 2.6.0.
+
+* Sat Jun 07 2014 Fedora Release Engineering - 2.5.2-3
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_21_Mass_Rebuild
+
+* Fri May 09 2014 Dennis Gilmore - 2.5.2-2
+- Redbuild for python 3.4
+
+* Fri Apr 18 2014 Thomas Moschny - 2.5.2-1
+- Update to 2.5.2.
+
+* Mon Oct 7 2013 Thomas Moschny - 2.4.2-2
+- Only run tests from the 'testing' subdir in %%check.
+
+* Sat Oct 5 2013 Thomas Moschny - 2.4.2-1
+- Update to 2.4.2.
+- Add buildroot's bindir to PATH while running the testsuite.
+
+* Sun Aug 04 2013 Fedora Release Engineering - 2.3.5-4
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_20_Mass_Rebuild
+
+* Thu Jun 13 2013 Thomas Moschny - 2.3.5-3
+- Disable tests using pexpect for now, fails on F19.
+
+* Wed Jun 12 2013 Thomas Moschny - 2.3.5-2
+- Use python-sphinx for rhel > 6 (rhbz#973318).
+- Update BR to use python-pexpect instead of pexpect.
+
+* Sat May 25 2013 Thomas Moschny - 2.3.5-1
+- Update to 2.3.5.
+- Docutils needed now to build README.html.
+- Add some BR optionally used by the testsuite.
+
+* Thu Feb 14 2013 Fedora Release Engineering - 2.3.4-2
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_19_Mass_Rebuild
+
+* Fri Nov 23 2012 Thomas Moschny - 2.3.4-1
+- Update to 2.3.4.
+
+* Sun Oct 28 2012 Thomas Moschny - 2.3.2-1
+- Update to 2.3.2.
+
+* Sun Oct 21 2012 Thomas Moschny - 2.3.1-1
+- Update to 2.3.1.
+- Re-enable some tests, ignore others.
+- Docs are available in English and Japanese now.
+
+* Thu Oct 11 2012 Thomas Moschny - 2.2.4-4
+- Add conditional for sphinx on rhel.
+- Remove rhel logic from with_python3 conditional.
+- Disable failing tests for Python3.
+
+* Sat Aug 04 2012 David Malcolm - 2.2.4-3
+- rebuild for https://fedoraproject.org/wiki/Features/Python_3.3
+
+* Sat Jul 21 2012 Fedora Release Engineering - 2.2.4-2
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild
+
+* Wed Jun 6 2012 Thomas Moschny - 2.2.4-1
+- Update to 2.2.4.
+
+* Wed Feb 8 2012 Thomas Moschny - 2.2.3-1
+- Update to 2.2.3.
+
+* Sat Jan 14 2012 Fedora Release Engineering - 2.2.1-2
+- Rebuilt for https://fedoraproject.org/wiki/Fedora_17_Mass_Rebuild
+
+* Sat Dec 17 2011 Thomas Moschny - 2.2.1-1
+- Update to 2.2.1.
+
+* Tue Dec 13 2011 Thomas Moschny - 2.2.0-1
+- Update to 2.2.0.
+
+* Wed Oct 26 2011 Thomas Moschny - 2.1.3-1
+- Update to 2.1.3.
+
+* Tue Sep 27 2011 Thomas Moschny - 2.1.2-1
+- Update to 2.1.2.
+
+* Sat Sep 3 2011 Thomas Moschny - 2.1.1-2
+- Fix: python3 dependencies.
+
+* Sun Aug 28 2011 Thomas Moschny - 2.1.1-1
+- Update to 2.1.1.
+
+* Thu Aug 11 2011 Thomas Moschny - 2.1.0-2
+- Update Requires and BuildRequires tags.
+
+* Tue Aug 9 2011 Thomas Moschny - 2.1.0-1
+- Update to 2.1.0.
+
+* Mon May 30 2011 Thomas Moschny - 2.0.3-1
+- Update to 2.0.3.
+
+* Thu Mar 17 2011 Thomas Moschny - 2.0.2-1
+- Update to 2.0.2.
+
+* Sun Jan 16 2011 Thomas Moschny - 2.0.0-1
+- New package.
diff --git a/plans.fmf b/plans.fmf
new file mode 100644
index 0000000..c5c5f7a
--- /dev/null
+++ b/plans.fmf
@@ -0,0 +1,11 @@
+discover:
+ - name: Smoke-tests
+ how: shell
+ tests:
+ - name: python-import-test
+ test: python3 -c 'import pytest'
+ require:
+ - python3-pytest
+ duration: 1m
+execute:
+ how: tmt
diff --git a/pytest.spec b/pytest.spec
new file mode 100644
index 0000000..988c984
--- /dev/null
+++ b/pytest.spec
@@ -0,0 +1,191 @@
+Name: pytest
+Version: 8.3.5
+Release: %autorelease
+Summary: Simple powerful testing with Python
+# SPDX
+License: MIT
+URL: https://pytest.org
+Source: %{pypi_source pytest %{version}}
+
+# Compatibility fix for attrs 25.2+
+Patch: https://github.com/pytest-dev/pytest/pull/13291.patch
+
+# Officially support Python 3.14
+# This fixes/xfails Python 3.14 test failures
+# Rebased from https://github.com/pytest-dev/pytest/pull/13440
+Patch: 13440.patch
+
+# Fix compatibility with Twisted 25
+# Rebased from https://github.com/pytest-dev/pytest/pull/13502
+Patch: 13502.patch
+
+# Fix test_doctest_unexpected_exception on Python 3.14
+Patch: https://github.com/pytest-dev/pytest/pull/13548.patch
+
+# Remove -s from Python shebang,
+# ensure that packages installed with pip to user locations are testable
+# https://bugzilla.redhat.com/2152171
+%undefine _py3_shebang_s
+
+# When building pytest for the first time with new Python version
+# we might not yet have all the BRs, those conditionals allow us to do that.
+
+# This can be used to disable all tests for faster bootstrapping.
+# The tests are enabled by default except when building on RHEL/ELN
+# (to avoid pulling in extra dependencies into next RHEL).
+%bcond tests %{undefined rhel}
+
+# Only disabling the optional tests is a more complex but careful approach
+# Pytest will skip the related tests, so we only conditionalize the BRs
+%bcond optional_tests %{with tests}
+
+# To run the tests in %%check we use pytest-timeout
+# When building pytest for the first time with new Python version
+# that is not possible as it depends on pytest
+%bcond timeout %{with tests}
+
+# When building pytest for the first time with new Python version
+# we also don't have sphinx yet and cannot build docs.
+# The docs are enabled by default except when building on RHEL/ELN
+# (to avoid pulling in extra dependencies into next RHEL).
+%bcond docs %{undefined rhel}
+
+BuildRequires: python3-devel
+BuildRequires: pyproject-rpm-macros >= 0-51
+
+%if %{with tests}
+# we avoid using %%pyproject_buildrequires -x testing as it mixes optional and non-optional deps
+BuildRequires: python3-attrs >= 19.2
+BuildRequires: python3-hypothesis >= 3.56
+BuildRequires: python3-pygments >= 2.7.2
+BuildRequires: python3-xmlschema
+%if %{with optional_tests}
+BuildRequires: python3-argcomplete
+#BuildRequires: python3-asynctest -- not packaged in Fedora
+BuildRequires: python3-decorator
+BuildRequires: python3-jinja2
+BuildRequires: python3-mock
+BuildRequires: python3-numpy
+BuildRequires: python3-pexpect
+BuildRequires: python3-pytest-xdist
+BuildRequires: python3-twisted
+BuildRequires: /usr/bin/lsof
+%endif
+%if %{with timeout}
+BuildRequires: python3-pytest-timeout
+%endif
+%endif
+
+%if %{with docs}
+BuildRequires: %{_bindir}/rst2html
+# pluggy >= 1 is needed to build the docs, older versions are allowed on runtime:
+BuildRequires: python3-pluggy >= 1
+BuildRequires: python3-pygments-pytest
+BuildRequires: python3-furo
+BuildRequires: python3-sphinx
+BuildRequires: python3-sphinx-removed-in
+BuildRequires: python3-sphinxcontrib-trio
+# See doc/en/conf.py -- sphinxcontrib.inkscapeconverter is only used when inkscape is available
+# we don't BR inkscape so we generally don't need it, but in case inkscape is installed accidentally:
+BuildRequires: (python3-sphinxcontrib-inkscapeconverter if inkscape)
+BuildRequires: make
+%endif
+
+BuildArch: noarch
+
+%description
+The pytest framework makes it easy to write small tests, yet scales to support
+complex functional testing for applications and libraries.
+
+
+%package -n python3-%{name}
+Summary: Simple powerful testing with Python
+Provides: pytest = %{version}-%{release}
+
+%description -n python3-%{name}
+The pytest framework makes it easy to write small tests, yet scales to support
+complex functional testing for applications and libraries.
+
+
+%prep
+%autosetup -p1 -n %{name}-%{version}
+
+# documentation dependencies missing in Fedora
+sed -i '/sphinxcontrib-towncrier/d' doc/en/requirements.txt
+sed -i '/sphinxcontrib\.towncrier/d' doc/en/conf.py
+sed -i '/sphinx_issues/d' doc/en/conf.py
+sed -i '/sphinx-issues/d' doc/en/requirements.txt
+
+
+%generate_buildrequires
+%pyproject_buildrequires -r
+
+
+%build
+%pyproject_wheel
+
+%if %{with docs}
+for l in doc/* ; do
+ %make_build -C $l html PYTHONPATH="$(pwd)/src"
+done
+for f in README CHANGELOG CONTRIBUTING ; do
+ rst2html ${f}.rst > ${f}.html
+done
+%endif
+
+
+%install
+%pyproject_install
+%pyproject_save_files _pytest pytest py
+
+mv %{buildroot}%{_bindir}/pytest %{buildroot}%{_bindir}/pytest-%{python3_version}
+ln -snf pytest-%{python3_version} %{buildroot}%{_bindir}/pytest-3
+mv %{buildroot}%{_bindir}/py.test %{buildroot}%{_bindir}/py.test-%{python3_version}
+ln -snf py.test-%{python3_version} %{buildroot}%{_bindir}/py.test-3
+
+# We use 3.X per default
+ln -snf pytest-%{python3_version} %{buildroot}%{_bindir}/pytest
+ln -snf py.test-%{python3_version} %{buildroot}%{_bindir}/py.test
+
+%if %{with docs}
+mkdir -p _htmldocs/html
+for l in doc/* ; do
+ # remove hidden file
+ rm ${l}/_build/html/.buildinfo
+ mv ${l}/_build/html _htmldocs/html/${l##doc/}
+done
+%endif
+
+# remove shebangs from all scripts
+find %{buildroot}%{python3_sitelib} \
+ -name '*.py' \
+ -exec sed -i -e '1{/^#!/d}' {} \;
+
+
+%check
+%if %{with tests}
+%global __pytest %{buildroot}%{_bindir}/pytest
+# optional_tests deps contain pytest-xdist, so we can use it to run tests faster
+%pytest testing %{?with_timeout:--timeout=30} %{?with_optional_tests:-n auto} -rs
+%else
+%pyproject_check_import
+%endif
+
+
+%files -n python3-%{name} -f %{pyproject_files}
+%if %{with docs}
+%doc CHANGELOG.html
+%doc README.html
+%doc CONTRIBUTING.html
+%doc _htmldocs/html
+%endif
+%{_bindir}/pytest
+%{_bindir}/pytest-3
+%{_bindir}/pytest-%{python3_version}
+%{_bindir}/py.test
+%{_bindir}/py.test-3
+%{_bindir}/py.test-%{python3_version}
+
+
+%changelog
+%autochangelog
diff --git a/sources b/sources
new file mode 100644
index 0000000..abd4d20
--- /dev/null
+++ b/sources
@@ -0,0 +1 @@
+SHA512 (pytest-8.3.5.tar.gz) = 386573a40f78c1dc864a0af7d765d49e9e91a38dd61bef95b07631bffba0806b34264622a998e849727f50fb220ada7b8242f7f7dbd501408e7bf4701d36589d