Skip to content

Commit 6e26c2b

Browse files
authored
Merge pull request #10898 from pytest-dev/backport-10893-to-7.3.x
[7.3.x] Python 3.12 alpha fixes
2 parents 1a427d3 + 23cf1fe commit 6e26c2b

File tree

5 files changed

+36
-13
lines changed

5 files changed

+36
-13
lines changed

changelog/10875.improvement.rst

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Python 3.12 support: fixed ``RuntimeError: TestResult has no addDuration method`` when running ``unittest`` tests.

changelog/10890.improvement.rst

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Python 3.12 support: fixed ``shutil.rmtree(onerror=...)`` deprecation warning when using :fixture:`tmp_path`.

src/_pytest/pathlib.py

+25-7
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
import os
77
import shutil
88
import sys
9+
import types
910
import uuid
1011
import warnings
1112
from enum import Enum
@@ -28,6 +29,8 @@
2829
from typing import Iterator
2930
from typing import Optional
3031
from typing import Set
32+
from typing import Tuple
33+
from typing import Type
3134
from typing import TypeVar
3235
from typing import Union
3336

@@ -63,21 +66,33 @@ def get_lock_path(path: _AnyPurePath) -> _AnyPurePath:
6366
return path.joinpath(".lock")
6467

6568

66-
def on_rm_rf_error(func, path: str, exc, *, start_path: Path) -> bool:
69+
def on_rm_rf_error(
70+
func,
71+
path: str,
72+
excinfo: Union[
73+
BaseException,
74+
Tuple[Type[BaseException], BaseException, Optional[types.TracebackType]],
75+
],
76+
*,
77+
start_path: Path,
78+
) -> bool:
6779
"""Handle known read-only errors during rmtree.
6880
6981
The returned value is used only by our own tests.
7082
"""
71-
exctype, excvalue = exc[:2]
83+
if isinstance(excinfo, BaseException):
84+
exc = excinfo
85+
else:
86+
exc = excinfo[1]
7287

7388
# Another process removed the file in the middle of the "rm_rf" (xdist for example).
7489
# More context: https://github.com/pytest-dev/pytest/issues/5974#issuecomment-543799018
75-
if isinstance(excvalue, FileNotFoundError):
90+
if isinstance(exc, FileNotFoundError):
7691
return False
7792

78-
if not isinstance(excvalue, PermissionError):
93+
if not isinstance(exc, PermissionError):
7994
warnings.warn(
80-
PytestWarning(f"(rm_rf) error removing {path}\n{exctype}: {excvalue}")
95+
PytestWarning(f"(rm_rf) error removing {path}\n{type(exc)}: {exc}")
8196
)
8297
return False
8398

@@ -86,7 +101,7 @@ def on_rm_rf_error(func, path: str, exc, *, start_path: Path) -> bool:
86101
warnings.warn(
87102
PytestWarning(
88103
"(rm_rf) unknown function {} when removing {}:\n{}: {}".format(
89-
func, path, exctype, excvalue
104+
func, path, type(exc), exc
90105
)
91106
)
92107
)
@@ -149,7 +164,10 @@ def rm_rf(path: Path) -> None:
149164
are read-only."""
150165
path = ensure_extended_length_path(path)
151166
onerror = partial(on_rm_rf_error, start_path=path)
152-
shutil.rmtree(str(path), onerror=onerror)
167+
if sys.version_info >= (3, 12):
168+
shutil.rmtree(str(path), onexc=onerror)
169+
else:
170+
shutil.rmtree(str(path), onerror=onerror)
153171

154172

155173
def find_prefixed(root: Path, prefix: str) -> Iterator[Path]:

src/_pytest/unittest.py

+3
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,9 @@ def addSuccess(self, testcase: "unittest.TestCase") -> None:
298298
def stopTest(self, testcase: "unittest.TestCase") -> None:
299299
pass
300300

301+
def addDuration(self, testcase: "unittest.TestCase", elapsed: float) -> None:
302+
pass
303+
301304
def runtest(self) -> None:
302305
from _pytest.debugging import maybe_wrap_pytest_function_for_tracing
303306

testing/test_tmpdir.py

+6-6
Original file line numberDiff line numberDiff line change
@@ -512,33 +512,33 @@ def test_on_rm_rf_error(self, tmp_path: Path) -> None:
512512

513513
# unknown exception
514514
with pytest.warns(pytest.PytestWarning):
515-
exc_info1 = (None, RuntimeError(), None)
515+
exc_info1 = (RuntimeError, RuntimeError(), None)
516516
on_rm_rf_error(os.unlink, str(fn), exc_info1, start_path=tmp_path)
517517
assert fn.is_file()
518518

519519
# we ignore FileNotFoundError
520-
exc_info2 = (None, FileNotFoundError(), None)
520+
exc_info2 = (FileNotFoundError, FileNotFoundError(), None)
521521
assert not on_rm_rf_error(None, str(fn), exc_info2, start_path=tmp_path)
522522

523523
# unknown function
524524
with pytest.warns(
525525
pytest.PytestWarning,
526-
match=r"^\(rm_rf\) unknown function None when removing .*foo.txt:\nNone: ",
526+
match=r"^\(rm_rf\) unknown function None when removing .*foo.txt:\n<class 'PermissionError'>: ",
527527
):
528-
exc_info3 = (None, PermissionError(), None)
528+
exc_info3 = (PermissionError, PermissionError(), None)
529529
on_rm_rf_error(None, str(fn), exc_info3, start_path=tmp_path)
530530
assert fn.is_file()
531531

532532
# ignored function
533533
with warnings.catch_warnings():
534534
warnings.simplefilter("ignore")
535535
with pytest.warns(None) as warninfo: # type: ignore[call-overload]
536-
exc_info4 = (None, PermissionError(), None)
536+
exc_info4 = PermissionError()
537537
on_rm_rf_error(os.open, str(fn), exc_info4, start_path=tmp_path)
538538
assert fn.is_file()
539539
assert not [x.message for x in warninfo]
540540

541-
exc_info5 = (None, PermissionError(), None)
541+
exc_info5 = PermissionError()
542542
on_rm_rf_error(os.unlink, str(fn), exc_info5, start_path=tmp_path)
543543
assert not fn.is_file()
544544

0 commit comments

Comments
 (0)