Add Python 3.13 (beta1) support

This commit is contained in:
Ran Benita 2024-05-17 09:59:29 +03:00
parent dbee3fa34a
commit 1cb704ff2c
10 changed files with 45 additions and 13 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

@ -1,6 +1,7 @@
# mypy: allow-untyped-defs # mypy: allow-untyped-defs
import inspect import inspect
from pathlib import Path from pathlib import Path
import sys
import textwrap import textwrap
from typing import Callable from typing import Callable
from typing import Optional from typing import Optional
@ -223,6 +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 ()),
' 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",
@ -379,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

@ -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