-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathconftest.py
More file actions
67 lines (47 loc) · 2.33 KB
/
Copy pathconftest.py
File metadata and controls
67 lines (47 loc) · 2.33 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
from __future__ import annotations
import logging
from os.path import splitext
from typing import TYPE_CHECKING, Generator, Optional, cast
import pytest
from tests.utils.gen_utils import GenUtils
if TYPE_CHECKING:
from pluggy import Result # runtime-optional (pluggy < 1.2), only needed for typing
logger: logging.Logger = logging.getLogger("conftest")
_NOT_SUPPORTED_HINTS: tuple[str, ...] = ("not supported", "does not support", "doesn't support")
def _crash_message(report: pytest.TestReport) -> str:
reprcrash: object = getattr(report.longrepr, "reprcrash", None)
message: Optional[str] = getattr(reprcrash, "message", None)
return str(message) if message else (report.longreprtext or "unknown")
def pytest_runtest_logreport(report: pytest.TestReport) -> None:
if report.outcome != "rerun": # type: ignore # set by pytest-rerunfailures
return
logger.error(f"EXPECTED FAILURE: {_crash_message(report)}")
logger.warning(f"RERUN {report.nodeid}")
def pytest_configure(config: pytest.Config) -> None:
# timestamp the log file so each run keeps its own
log_file: str = cast(str, config.getini("log_file"))
if not log_file:
return
name, ext = splitext(log_file)
config.option.log_file = f"{name}_{GenUtils.current_date_time_str()}{ext}"
def pytest_collection_modifyitems(items: list[pytest.Item]) -> None:
# `not_implemented` == non-strict xfail: xfails while it raises, xpasses once done
for item in items:
if item.get_closest_marker("not_implemented") is not None:
item.add_marker(pytest.mark.xfail(reason="not implemented", strict=False))
@pytest.hookimpl(hookwrapper=True)
def pytest_runtest_call(item: pytest.Item) -> Generator[None, Result[None], None]:
# `not_supported`: the inherited test must raise a "not supported" error;
# that's a pass, anything else (or no error) is a failure.
if item.get_closest_marker("not_supported") is None:
yield
return
outcome: Result[None] = yield
try:
outcome.get_result()
except Exception as error:
if any(hint in str(error).lower() for hint in _NOT_SUPPORTED_HINTS):
logger.debug(f"NOT SUPPORTED (as expected): {error}")
outcome.force_result(None)
return
outcome.force_exception(pytest.fail.Exception("Expected a 'not supported' error"))