Merge pull request #12334 from bluetech/py313
Add Python 3.13 (beta) support
This commit is contained in:
commit
c1d623cbff
|
@ -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"
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Support for Python 3.13 (beta1 at the time of writing).
|
|
@ -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",
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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}"
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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:",
|
||||||
|
|
|
@ -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:
|
||||||
|
|
Loading…
Reference in New Issue