Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[8.2.x] Add Python 3.13 (beta) support #12340

Merged
merged 1 commit into from
May 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 19 additions & 3 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ jobs:
"windows-py310",
"windows-py311",
"windows-py312",
"windows-py313",

"ubuntu-py38",
"ubuntu-py38-pluggy",
Expand All @@ -63,12 +64,14 @@ jobs:
"ubuntu-py310",
"ubuntu-py311",
"ubuntu-py312",
"ubuntu-py313",
"ubuntu-pypy3",

"macos-py38",
"macos-py39",
"macos-py310",
"macos-py312",
"macos-py313",

"doctesting",
"plugins",
Expand Down Expand Up @@ -97,9 +100,13 @@ jobs:
os: windows-latest
tox_env: "py311"
- name: "windows-py312"
python: "3.12-dev"
python: "3.12"
os: windows-latest
tox_env: "py312"
- name: "windows-py313"
python: "3.13-dev"
os: windows-latest
tox_env: "py313"

- name: "ubuntu-py38"
python: "3.8"
Expand Down Expand Up @@ -128,10 +135,15 @@ jobs:
tox_env: "py311"
use_coverage: true
- name: "ubuntu-py312"
python: "3.12-dev"
python: "3.12"
os: ubuntu-latest
tox_env: "py312"
use_coverage: true
- name: "ubuntu-py313"
python: "3.13-dev"
os: ubuntu-latest
tox_env: "py313"
use_coverage: true
- name: "ubuntu-pypy3"
python: "pypy-3.8"
os: ubuntu-latest
Expand All @@ -151,9 +163,13 @@ jobs:
os: macos-latest
tox_env: "py310-xdist"
- name: "macos-py312"
python: "3.12-dev"
python: "3.12"
os: macos-latest
tox_env: "py312-xdist"
- name: "macos-py313"
python: "3.13-dev"
os: macos-latest
tox_env: "py313-xdist"

- name: "plugins"
python: "3.12"
Expand Down
1 change: 1 addition & 0 deletions changelog/12334.improvement.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Support for Python 3.13 (beta1 at the time of writing).
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ classifiers = [
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Topic :: Software Development :: Libraries",
"Topic :: Software Development :: Testing",
"Topic :: Utilities",
Expand Down
7 changes: 3 additions & 4 deletions src/_pytest/_code/code.py
Original file line number Diff line number Diff line change
Expand Up @@ -424,15 +424,14 @@ def recursionindex(self) -> Optional[int]:
# which generates code objects that have hash/value equality
# XXX needs a test
key = entry.frame.code.path, id(entry.frame.code.raw), entry.lineno
# print "checking for recursion at", key
values = cache.setdefault(key, [])
# Since Python 3.13 f_locals is a proxy, freeze it.
loc = dict(entry.frame.f_locals)
if values:
f = entry.frame
loc = f.f_locals
for otherloc in values:
if otherloc == loc:
return i
values.append(entry.frame.f_locals)
values.append(loc)
return None


Expand Down
6 changes: 5 additions & 1 deletion src/_pytest/pytester.py
Original file line number Diff line number Diff line change
Expand Up @@ -289,7 +289,8 @@ def assert_contains(self, entries: Sequence[Tuple[str, str]]) -> None:
__tracebackhide__ = True
i = 0
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:
name, check = entries.pop(0)
for ind, call in enumerate(self.calls[i:]):
Expand Down Expand Up @@ -760,6 +761,9 @@ def _makefile(
) -> Path:
items = list(files.items())

if ext is None:
raise TypeError("ext must not be None")

if ext and not ext.startswith("."):
raise ValueError(
f"pytester.makefile expects a file extension, try .{ext} instead of {ext}"
Expand Down
8 changes: 6 additions & 2 deletions testing/code/test_excinfo.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# mypy: allow-untyped-defs
from __future__ import annotations

import fnmatch
import importlib
import io
import operator
Expand Down Expand Up @@ -237,7 +238,7 @@ def f(n):
n += 1
f(n)

excinfo = pytest.raises(RuntimeError, f, 8)
excinfo = pytest.raises(RecursionError, f, 8)
traceback = excinfo.traceback
recindex = traceback.recursionindex()
assert recindex == 3
Expand Down Expand Up @@ -373,7 +374,10 @@ def test_excinfo_no_sourcecode():
except ValueError:
excinfo = _pytest._code.ExceptionInfo.from_current()
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:
Expand Down
6 changes: 5 additions & 1 deletion testing/code/test_source.py
Original file line number Diff line number Diff line change
Expand Up @@ -370,7 +370,11 @@ class B:
pass

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:
Expand Down
2 changes: 1 addition & 1 deletion testing/test_cacheprovider.py
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ def test_custom_cache_dir_with_env_var(
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(
env: Sequence[str], pytester: Pytester, monkeypatch: MonkeyPatch
) -> None:
Expand Down
8 changes: 2 additions & 6 deletions testing/test_doctest.py
Original file line number Diff line number Diff line change
Expand Up @@ -224,11 +224,7 @@ def test_doctest_unexpected_exception(self, pytester: Pytester):
"Traceback (most recent call last):",
' File "*/doctest.py", line *, in __run',
" *",
*(
(" *^^^^*",)
if (3, 11, 0, "beta", 4) > sys.version_info >= (3, 11)
else ()
),
*((" *^^^^*", " *", " *") if sys.version_info >= (3, 13) else ()),
' File "<doctest test_doctest_unexpected_exception.txt[1]>", line 1, in <module>',
"ZeroDivisionError: division by zero",
"*/test_doctest_unexpected_exception.txt:2: UnexpectedException",
Expand Down Expand Up @@ -385,7 +381,7 @@ def some_property(self):
"*= FAILURES =*",
"*_ [[]doctest[]] test_doctest_linedata_on_property.Sample.some_property _*",
"004 ",
"005 >>> Sample().some_property",
"005 *>>> Sample().some_property",
"Expected:",
" 'another thing'",
"Got:",
Expand Down
17 changes: 1 addition & 16 deletions testing/test_main.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import os
from pathlib import Path
import re
import sys
from typing import Optional

from _pytest.config import ExitCode
Expand Down Expand Up @@ -45,32 +44,18 @@ def pytest_internalerror(excrepr, excinfo):
assert result.ret == ExitCode.INTERNAL_ERROR
assert result.stdout.lines[0] == "INTERNALERROR> Traceback (most recent call last):"

end_lines = (
result.stdout.lines[-4:]
if (3, 11, 0, "beta", 4) > sys.version_info >= (3, 11)
else result.stdout.lines[-3:]
)
end_lines = result.stdout.lines[-3:]

if exc == SystemExit:
assert end_lines == [
f'INTERNALERROR> File "{c1}", line 4, in pytest_sessionstart',
'INTERNALERROR> raise SystemExit("boom")',
*(
("INTERNALERROR> ^^^^^^^^^^^^^^^^^^^^^^^^",)
if (3, 11, 0, "beta", 4) > sys.version_info >= (3, 11)
else ()
),
"INTERNALERROR> SystemExit: boom",
]
else:
assert end_lines == [
f'INTERNALERROR> File "{c1}", line 4, in pytest_sessionstart',
'INTERNALERROR> raise ValueError("boom")',
*(
("INTERNALERROR> ^^^^^^^^^^^^^^^^^^^^^^^^",)
if (3, 11, 0, "beta", 4) > sys.version_info >= (3, 11)
else ()
),
"INTERNALERROR> ValueError: boom",
]
if returncode is False:
Expand Down
1 change: 1 addition & 0 deletions tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ envlist =
py310
py311
py312
py313
pypy3
py38-{pexpect,xdist,unittestextras,numpy,pluggymain,pylib}
doctesting
Expand Down
Loading