python3.14-pytest/13440.patch
2025-11-28 11:03:04 +01:00

618 lines
22 KiB
Diff

From a3a606005525922d35639efc3009db47fc50cbce Mon Sep 17 00:00:00 2001
From: Thomas Grainger <tagrain@gmail.com>
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 <tagrain@gmail.com>
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 <tagrain@gmail.com>
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 <tagrain@gmail.com>
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 <tagrain@gmail.com>
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 <tagrain@gmail.com>
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 <tagrain@gmail.com>
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 <tagrain@gmail.com>
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 <function BrokenDel.__del__ at *>: None"
+ )
+ if sys.version_info >= (3, 14)
+ else " * PytestUnraisableExceptionWarning: Exception ignored in: <function BrokenDel.__del__ at *>"
+)
+
@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: <function BrokenDel.__del__ at *>",
+ 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: <function BrokenDel.__del__ at *>",
+ 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: <function BrokenDel.__del__ at *>",
+ UNRAISABLE_LINE,
" ",
" Traceback (most recent call last):",
" ValueError: del is broken",
From 66a5284096584943f611f607358a2c29fac61d55 Mon Sep 17 00:00:00 2001
From: Thomas Grainger <tagrain@gmail.com>
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 <tagrain@gmail.com>
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 <tagrain@gmail.com>
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 <h6+github@pm.me>
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 <tagrain@gmail.com>
Date: Tue, 27 May 2025 12:34:25 +0100
Subject: [PATCH 15/19] Update changelog/13308.improvement.rst
Co-authored-by: Bruno Oliveira <bruno@soliv.dev>
---
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 <tagrain@gmail.com>
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 <tagrain@gmail.com>
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 <tagrain@gmail.com>
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: <urlopen error the url was bad>"
+ 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 <tagrain@gmail.com>
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