diff --git a/AUTHORS b/AUTHORS index e19a0ae5871..7f742fb4083 100644 --- a/AUTHORS +++ b/AUTHORS @@ -130,6 +130,7 @@ Daw-Ran Liou Debi Mishra Denis Kirisov Denivy Braiam Rück +Deysha Rivera Dheeraj C K Dhiren Serai Diego Russo diff --git a/changelog/13384.bugfix.rst b/changelog/13384.bugfix.rst new file mode 100644 index 00000000000..e93d01dcab0 --- /dev/null +++ b/changelog/13384.bugfix.rst @@ -0,0 +1 @@ +Fixed an issue where pytest could report negative durations. diff --git a/src/_pytest/junitxml.py b/src/_pytest/junitxml.py index d129cd295e7..06cab961ef5 100644 --- a/src/_pytest/junitxml.py +++ b/src/_pytest/junitxml.py @@ -637,6 +637,7 @@ def pytest_internalerror(self, excrepr: ExceptionRepr) -> None: def pytest_sessionstart(self) -> None: self.suite_start_time = timing.time() + self.suite_start_perf = timing.perf_counter() def pytest_sessionfinish(self) -> None: dirname = os.path.dirname(os.path.abspath(self.logfile)) @@ -644,8 +645,8 @@ def pytest_sessionfinish(self) -> None: os.makedirs(dirname, exist_ok=True) with open(self.logfile, "w", encoding="utf-8") as logfile: - suite_stop_time = timing.time() - suite_time_delta = suite_stop_time - self.suite_start_time + suite_stop_perf = timing.perf_counter() + suite_time_delta = suite_stop_perf - self.suite_start_perf numtests = ( self.stats["passed"] diff --git a/src/_pytest/pytester.py b/src/_pytest/pytester.py index 59839562031..bb5f6a5787e 100644 --- a/src/_pytest/pytester.py +++ b/src/_pytest/pytester.py @@ -1150,7 +1150,7 @@ def runpytest_inprocess( if syspathinsert: self.syspathinsert() - now = timing.time() + now = timing.perf_counter() capture = _get_multicapture("sys") capture.start_capturing() try: @@ -1180,7 +1180,7 @@ class reprec: # type: ignore assert reprec.ret is not None res = RunResult( - reprec.ret, out.splitlines(), err.splitlines(), timing.time() - now + reprec.ret, out.splitlines(), err.splitlines(), timing.perf_counter() - now ) res.reprec = reprec # type: ignore return res @@ -1408,7 +1408,7 @@ def run( print(" in:", Path.cwd()) with p1.open("w", encoding="utf8") as f1, p2.open("w", encoding="utf8") as f2: - now = timing.time() + now = timing.perf_counter() popen = self.popen( cmdargs, stdin=stdin, @@ -1445,7 +1445,7 @@ def handle_timeout() -> None: with contextlib.suppress(ValueError): ret = ExitCode(ret) - return RunResult(ret, out, err, timing.time() - now) + return RunResult(ret, out, err, timing.perf_counter() - now) def _dump_lines(self, lines, fp): try: diff --git a/src/_pytest/terminal.py b/src/_pytest/terminal.py index 3297c38e848..8415912e9ac 100644 --- a/src/_pytest/terminal.py +++ b/src/_pytest/terminal.py @@ -769,7 +769,7 @@ def pytest_collection(self) -> None: if self.isatty: if self.config.option.verbose >= 0: self.write("collecting ... ", flush=True, bold=True) - self._collect_report_last_write = timing.time() + self._collect_report_last_write = timing.perf_counter() elif self.config.option.verbose >= 1: self.write("collecting ... ", flush=True, bold=True) @@ -789,7 +789,7 @@ def report_collect(self, final: bool = False) -> None: if not final: # Only write "collecting" report every 0.5s. - t = timing.time() + t = timing.perf_counter() if ( self._collect_report_last_write is not None and self._collect_report_last_write > t - REPORT_COLLECTING_RESOLUTION @@ -823,7 +823,7 @@ def report_collect(self, final: bool = False) -> None: @hookimpl(trylast=True) def pytest_sessionstart(self, session: Session) -> None: self._session = session - self._sessionstarttime = timing.time() + self._sessionstarttime = timing.perf_counter() if not self.showheader: return self.write_sep("=", "test session starts", bold=True) @@ -1202,7 +1202,7 @@ def summary_stats(self) -> None: if self.verbosity < -1: return - session_duration = timing.time() - self._sessionstarttime + session_duration = timing.perf_counter() - self._sessionstarttime (parts, main_color) = self.build_summary_stats_line() line_parts = [] diff --git a/testing/_py/test_local.py b/testing/_py/test_local.py index 03a828c64f0..e4b011a9727 100644 --- a/testing/_py/test_local.py +++ b/testing/_py/test_local.py @@ -12,6 +12,7 @@ from py import error from py.path import local +import _pytest.timing import pytest @@ -738,7 +739,6 @@ def test_dump(self, tmpdir, bin): def test_setmtime(self): import tempfile - import time try: fd, name = tempfile.mkstemp() @@ -747,7 +747,7 @@ def test_setmtime(self): name = tempfile.mktemp() open(name, "w").close() try: - mtime = int(time.time()) - 100 + mtime = int(_pytest.timing.time()) - 100 path = local(name) assert path.mtime() != mtime path.setmtime(mtime) @@ -1405,7 +1405,7 @@ def test_atime(self, tmpdir): import time path = tmpdir.ensure("samplefile") - now = time.time() + now = _pytest.timing.perf_counter() atime1 = path.atime() # we could wait here but timer resolution is very # system dependent @@ -1413,7 +1413,7 @@ def test_atime(self, tmpdir): time.sleep(ATIME_RESOLUTION) atime2 = path.atime() time.sleep(ATIME_RESOLUTION) - duration = time.time() - now + duration = _pytest.timing.perf_counter() - now assert (atime2 - atime1) <= duration def test_commondir(self, path1): diff --git a/testing/test_pytester.py b/testing/test_pytester.py index 87714b4708f..555d73f9eaa 100644 --- a/testing/test_pytester.py +++ b/testing/test_pytester.py @@ -4,7 +4,6 @@ import os import subprocess import sys -import time from types import ModuleType from _pytest.config import ExitCode @@ -16,6 +15,7 @@ from _pytest.pytester import Pytester from _pytest.pytester import SysModulesSnapshot from _pytest.pytester import SysPathsSnapshot +import _pytest.timing import pytest @@ -451,9 +451,9 @@ def test_pytester_run_with_timeout(pytester: Pytester) -> None: timeout = 120 - start = time.time() + start = _pytest.timing.perf_counter() result = pytester.runpytest_subprocess(testfile, timeout=timeout) - end = time.time() + end = _pytest.timing.perf_counter() duration = end - start assert result.ret == ExitCode.OK