Merge pull request #12334 from bluetech/py313

Add Python 3.13 (beta) support
This commit is contained in:
Ran Benita 2024-05-19 09:45:09 +03:00 committed by GitHub
commit c1d623cbff
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 45 additions and 34 deletions

View File

@ -55,6 +55,7 @@ jobs:
"windows-py310", "windows-py310",
"windows-py311", "windows-py311",
"windows-py312", "windows-py312",
"windows-py313",
"ubuntu-py38", "ubuntu-py38",
"ubuntu-py38-pluggy", "ubuntu-py38-pluggy",
@ -63,12 +64,14 @@ jobs:
"ubuntu-py310", "ubuntu-py310",
"ubuntu-py311", "ubuntu-py311",
"ubuntu-py312", "ubuntu-py312",
"ubuntu-py313",
"ubuntu-pypy3", "ubuntu-pypy3",
"macos-py38", "macos-py38",
"macos-py39", "macos-py39",
"macos-py310", "macos-py310",
"macos-py312", "macos-py312",
"macos-py313",
"doctesting", "doctesting",
"plugins", "plugins",
@ -97,9 +100,13 @@ jobs:
os: windows-latest os: windows-latest
tox_env: "py311" tox_env: "py311"
- name: "windows-py312" - name: "windows-py312"
python: "3.12-dev" python: "3.12"
os: windows-latest os: windows-latest
tox_env: "py312" tox_env: "py312"
- name: "windows-py313"
python: "3.13-dev"
os: windows-latest
tox_env: "py313"
- name: "ubuntu-py38" - name: "ubuntu-py38"
python: "3.8" python: "3.8"
@ -128,10 +135,15 @@ jobs:
tox_env: "py311" tox_env: "py311"
use_coverage: true use_coverage: true
- name: "ubuntu-py312" - name: "ubuntu-py312"
python: "3.12-dev" python: "3.12"
os: ubuntu-latest os: ubuntu-latest
tox_env: "py312" tox_env: "py312"
use_coverage: true use_coverage: true
- name: "ubuntu-py313"
python: "3.13-dev"
os: ubuntu-latest
tox_env: "py313"
use_coverage: true
- name: "ubuntu-pypy3" - name: "ubuntu-pypy3"
python: "pypy-3.8" python: "pypy-3.8"
os: ubuntu-latest os: ubuntu-latest
@ -151,9 +163,13 @@ jobs:
os: macos-latest os: macos-latest
tox_env: "py310-xdist" tox_env: "py310-xdist"
- name: "macos-py312" - name: "macos-py312"
python: "3.12-dev" python: "3.12"
os: macos-latest os: macos-latest
tox_env: "py312-xdist" tox_env: "py312-xdist"
- name: "macos-py313"
python: "3.13-dev"
os: macos-latest
tox_env: "py313-xdist"
- name: "plugins" - name: "plugins"
python: "3.12" python: "3.12"

View File

@ -0,0 +1 @@
Support for Python 3.13 (beta1 at the time of writing).

View File

@ -31,6 +31,7 @@ classifiers = [
"Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Topic :: Software Development :: Libraries", "Topic :: Software Development :: Libraries",
"Topic :: Software Development :: Testing", "Topic :: Software Development :: Testing",
"Topic :: Utilities", "Topic :: Utilities",

View File

@ -424,15 +424,14 @@ class Traceback(List[TracebackEntry]):
# which generates code objects that have hash/value equality # which generates code objects that have hash/value equality
# XXX needs a test # XXX needs a test
key = entry.frame.code.path, id(entry.frame.code.raw), entry.lineno key = entry.frame.code.path, id(entry.frame.code.raw), entry.lineno
# print "checking for recursion at", key
values = cache.setdefault(key, []) values = cache.setdefault(key, [])
# Since Python 3.13 f_locals is a proxy, freeze it.
loc = dict(entry.frame.f_locals)
if values: if values:
f = entry.frame
loc = f.f_locals
for otherloc in values: for otherloc in values:
if otherloc == loc: if otherloc == loc:
return i return i
values.append(entry.frame.f_locals) values.append(loc)
return None return None

View File

@ -289,7 +289,8 @@ class HookRecorder:
__tracebackhide__ = True __tracebackhide__ = True
i = 0 i = 0
entries = list(entries) entries = list(entries)
backlocals = sys._getframe(1).f_locals # Since Python 3.13, f_locals is not a dict, but eval requires a dict.
backlocals = dict(sys._getframe(1).f_locals)
while entries: while entries:
name, check = entries.pop(0) name, check = entries.pop(0)
for ind, call in enumerate(self.calls[i:]): for ind, call in enumerate(self.calls[i:]):
@ -760,6 +761,9 @@ class Pytester:
) -> Path: ) -> Path:
items = list(files.items()) items = list(files.items())
if ext is None:
raise TypeError("ext must not be None")
if ext and not ext.startswith("."): if ext and not ext.startswith("."):
raise ValueError( raise ValueError(
f"pytester.makefile expects a file extension, try .{ext} instead of {ext}" f"pytester.makefile expects a file extension, try .{ext} instead of {ext}"

View File

@ -1,6 +1,7 @@
# mypy: allow-untyped-defs # mypy: allow-untyped-defs
from __future__ import annotations from __future__ import annotations
import fnmatch
import importlib import importlib
import io import io
import operator import operator
@ -237,7 +238,7 @@ class TestTraceback_f_g_h:
n += 1 n += 1
f(n) f(n)
excinfo = pytest.raises(RuntimeError, f, 8) excinfo = pytest.raises(RecursionError, f, 8)
traceback = excinfo.traceback traceback = excinfo.traceback
recindex = traceback.recursionindex() recindex = traceback.recursionindex()
assert recindex == 3 assert recindex == 3
@ -373,7 +374,10 @@ def test_excinfo_no_sourcecode():
except ValueError: except ValueError:
excinfo = _pytest._code.ExceptionInfo.from_current() excinfo = _pytest._code.ExceptionInfo.from_current()
s = str(excinfo.traceback[-1]) s = str(excinfo.traceback[-1])
assert s == " File '<string>':1 in <module>\n ???\n" # TODO: Since Python 3.13b1 under pytest-xdist, the * is `import
# sys;exec(eval(sys.stdin.readline()))` (execnet bootstrap code)
# instead of `???` like before. Is this OK?
fnmatch.fnmatch(s, " File '<string>':1 in <module>\n *\n")
def test_excinfo_no_python_sourcecode(tmp_path: Path) -> None: def test_excinfo_no_python_sourcecode(tmp_path: Path) -> None:

View File

@ -370,7 +370,11 @@ def test_getfslineno() -> None:
pass pass
B.__name__ = B.__qualname__ = "B2" B.__name__ = B.__qualname__ = "B2"
assert getfslineno(B)[1] == -1 # Since Python 3.13 this started working.
if sys.version_info >= (3, 13):
assert getfslineno(B)[1] != -1
else:
assert getfslineno(B)[1] == -1
def test_code_of_object_instance_with_call() -> None: def test_code_of_object_instance_with_call() -> None:

View File

@ -194,7 +194,7 @@ class TestNewAPI:
assert pytester.path.joinpath("custom_cache_dir").is_dir() assert pytester.path.joinpath("custom_cache_dir").is_dir()
@pytest.mark.parametrize("env", ((), ("TOX_ENV_DIR", "/tox_env_dir"))) @pytest.mark.parametrize("env", ((), ("TOX_ENV_DIR", "mydir/tox-env")))
def test_cache_reportheader( def test_cache_reportheader(
env: Sequence[str], pytester: Pytester, monkeypatch: MonkeyPatch env: Sequence[str], pytester: Pytester, monkeypatch: MonkeyPatch
) -> None: ) -> None:

View File

@ -224,11 +224,7 @@ class TestDoctests:
"Traceback (most recent call last):", "Traceback (most recent call last):",
' File "*/doctest.py", line *, in __run', ' File "*/doctest.py", line *, in __run',
" *", " *",
*( *((" *^^^^*", " *", " *") if sys.version_info >= (3, 13) else ()),
(" *^^^^*",)
if (3, 11, 0, "beta", 4) > sys.version_info >= (3, 11)
else ()
),
' File "<doctest test_doctest_unexpected_exception.txt[1]>", line 1, in <module>', ' File "<doctest test_doctest_unexpected_exception.txt[1]>", line 1, in <module>',
"ZeroDivisionError: division by zero", "ZeroDivisionError: division by zero",
"*/test_doctest_unexpected_exception.txt:2: UnexpectedException", "*/test_doctest_unexpected_exception.txt:2: UnexpectedException",
@ -385,7 +381,7 @@ class TestDoctests:
"*= FAILURES =*", "*= FAILURES =*",
"*_ [[]doctest[]] test_doctest_linedata_on_property.Sample.some_property _*", "*_ [[]doctest[]] test_doctest_linedata_on_property.Sample.some_property _*",
"004 ", "004 ",
"005 >>> Sample().some_property", "005 *>>> Sample().some_property",
"Expected:", "Expected:",
" 'another thing'", " 'another thing'",
"Got:", "Got:",

View File

@ -3,7 +3,6 @@ import argparse
import os import os
from pathlib import Path from pathlib import Path
import re import re
import sys
from typing import Optional from typing import Optional
from _pytest.config import ExitCode from _pytest.config import ExitCode
@ -45,32 +44,18 @@ def test_wrap_session_notify_exception(ret_exc, pytester: Pytester) -> None:
assert result.ret == ExitCode.INTERNAL_ERROR assert result.ret == ExitCode.INTERNAL_ERROR
assert result.stdout.lines[0] == "INTERNALERROR> Traceback (most recent call last):" assert result.stdout.lines[0] == "INTERNALERROR> Traceback (most recent call last):"
end_lines = ( end_lines = result.stdout.lines[-3:]
result.stdout.lines[-4:]
if (3, 11, 0, "beta", 4) > sys.version_info >= (3, 11)
else result.stdout.lines[-3:]
)
if exc == SystemExit: if exc == SystemExit:
assert end_lines == [ assert end_lines == [
f'INTERNALERROR> File "{c1}", line 4, in pytest_sessionstart', f'INTERNALERROR> File "{c1}", line 4, in pytest_sessionstart',
'INTERNALERROR> raise SystemExit("boom")', 'INTERNALERROR> raise SystemExit("boom")',
*(
("INTERNALERROR> ^^^^^^^^^^^^^^^^^^^^^^^^",)
if (3, 11, 0, "beta", 4) > sys.version_info >= (3, 11)
else ()
),
"INTERNALERROR> SystemExit: boom", "INTERNALERROR> SystemExit: boom",
] ]
else: else:
assert end_lines == [ assert end_lines == [
f'INTERNALERROR> File "{c1}", line 4, in pytest_sessionstart', f'INTERNALERROR> File "{c1}", line 4, in pytest_sessionstart',
'INTERNALERROR> raise ValueError("boom")', 'INTERNALERROR> raise ValueError("boom")',
*(
("INTERNALERROR> ^^^^^^^^^^^^^^^^^^^^^^^^",)
if (3, 11, 0, "beta", 4) > sys.version_info >= (3, 11)
else ()
),
"INTERNALERROR> ValueError: boom", "INTERNALERROR> ValueError: boom",
] ]
if returncode is False: if returncode is False:

View File

@ -9,6 +9,7 @@ envlist =
py310 py310
py311 py311
py312 py312
py313
pypy3 pypy3
py38-{pexpect,xdist,unittestextras,numpy,pluggymain,pylib} py38-{pexpect,xdist,unittestextras,numpy,pluggymain,pylib}
doctesting doctesting