File: conftest.py

package info (click to toggle)
python-choreographer 1.2.1-4
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 660 kB
  • sloc: python: 2,841; makefile: 12; sh: 5
file content (119 lines) | stat: -rw-r--r-- 4,026 bytes parent folder | download
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
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
import asyncio
import logging

import choreographer as choreo
import logistro
import pytest
import pytest_asyncio
from choreographer import errors

_logger = logistro.getLogger(__name__)


@pytest.fixture(params=[True, False], ids=["enable_sandbox", ""])
def sandbox(request):
    return request.param


@pytest.fixture(params=[True, False], ids=["enable_gpu", ""])
def gpu(request):
    return request.param


@pytest.fixture(params=[True, False], ids=["headless", ""])
def headless(request):
    return request.param


@pytest.fixture
def project_root(request):
    return request.config.getoption("--project-root")


# --headless is the default flag for most tests,
# but you can set --no-headless if you want to watch
def pytest_addoption(parser):
    parser.addoption("--headless", action="store_true", dest="headless", default=True)
    parser.addoption("--no-headless", dest="headless", action="store_false")
    parser.addoption("--project-root", action="store", default=None, help="Project root directory")


# browser fixture will supply a browser for you
@pytest_asyncio.fixture(scope="function", loop_scope="function")
async def browser(request):
    _logger.info("Fixture building browser.")
    headless = request.config.getoption("--headless")
    browser = await choreo.Browser(
        headless=headless,
    )
    yield browser
    _logger.info("Fixture closing browser.")
    try:
        await browser.close()
    except errors.BrowserClosedError:
        pass
    if (
        hasattr(browser._browser_impl, "tmp_dir")  # noqa: SLF001
        and browser._browser_impl.tmp_dir.exists  # type: ignore[reportAttributeAccessIssue] # noqa: SLF001
    ):
        raise RuntimeError(
            "Temporary directory not deleted successfully: "
            f"{browser._browser_impl.tmp_dir.path}",  # type: ignore[reportAttributeAccessIssue] # noqa: SLF001
        )


# add a timeout if tests requests browser
# but if tests creates their own browser they are responsible
# a fixture can be used to specify the timeout: timeout=10
# else it uses pytest.default_timeout
@pytest.hookimpl(tryfirst=True, hookwrapper=True)
def pytest_runtest_setup(item):
    # not even sure if this working
    # typer doesn't like item: pytest.Item w/ funcargs
    # but this is the recommended way
    # some people say do trylast
    yield
    if "browser" in item.funcargs:
        _logger.info("Hook setting test timeout.")
        raw_test_fn = item.obj
        timeouts = [k for k in item.funcargs if k.startswith("timeout")]
        timeout = (
            item.funcargs[timeouts[-1]] if timeouts else pytest.default_timeout  # type: ignore[reportAttributeAccessIssue]
        )
        if (
            item.get_closest_marker("asyncio") and timeout
        ):  # "closest" because markers can be function/session/package etc

            async def wrapped_test_fn(*args, **kwargs):
                try:
                    return await asyncio.wait_for(
                        raw_test_fn(*args, **kwargs),
                        timeout=timeout,
                    )
                except TimeoutError:
                    pytest.fail(
                        f"Test {item.name} failed a timeout. "
                        "This can be extended, but shouldn't be. See conftest.py.",
                    )

            item.obj = wrapped_test_fn


def pytest_configure():
    # change this by command line TODO
    pytest.default_timeout = 20  # type: ignore[reportAttributeAccessIssue]


# pytest shuts down its capture before logging/threads finish
@pytest.fixture(scope="session", autouse=True)
def cleanup_logging_handlers(request):
    capture = request.config.getoption("--capture") != "no"
    try:
        yield
    finally:
        if capture:
            _logger.info("Conftest cleaning up handlers.")
            for handler in logging.root.handlers[:]:
                handler.flush()
                if isinstance(handler, logging.StreamHandler):
                    logging.root.removeHandler(handler)