1"""
2pytest hooks for interactive test cases.
3"""
4import inspect
5import pytest
6
7
8def pytest_collection_modifyitems(items, config):
9    """Determine whether test should be skipped based on command-line options."""
10    sanity = config.getoption('--sanity', False)
11    non_interactive = config.getoption('--non-interactive', False)
12
13    remaining = []
14    deselected = []
15    for item in items:
16        if _skip_item(item, sanity, non_interactive):
17            deselected.append(item)
18        else:
19            remaining.append(item)
20    if deselected:
21        items[:] = remaining
22        config.hook.pytest_deselected(items=deselected)
23
24
25def _skip_item(item, sanity, non_interactive):
26    requires_user_action = item.get_closest_marker('requires_user_action')
27    requires_user_validation = item.get_closest_marker('requires_user_validation')
28    only_interactive = item.get_closest_marker('only_interactive')
29
30    if ((requires_user_action is not None or only_interactive is not None)
31            and (sanity or non_interactive)):
32        return True
33
34    if ((requires_user_validation is not None)
35            and (non_interactive)):
36        return True
37
38    return False
39
40def pytest_runtest_setup(item):
41    # TODO: Remove after migrating tests
42    sanity = item.config.getoption('--sanity', False)
43    non_interactive = item.config.getoption('--non-interactive', False)
44    interactive = not sanity and not non_interactive
45
46    if interactive:
47        _show_test_header(item)
48    _try_set_class_attribute(item, 'interactive', interactive)
49    _try_set_class_attribute(item, 'allow_missing_screenshots', sanity)
50
51def _show_test_header(item):
52    print()
53    print('='*80)
54    print(item.name)
55    print(_get_doc(item))
56    print('-'*80)
57
58def _try_set_class_attribute(item, name, value):
59    if hasattr(item.obj, 'im_class'):
60        if hasattr(item.obj.im_class, name):
61            setattr(item.obj.im_class, name, value)
62
63def _get_doc(item):
64    i = item
65    while i is not None:
66        if hasattr(i, 'obj') and hasattr(i.obj, '__doc__') and i.obj.__doc__ is not None:
67            return inspect.cleandoc(i.obj.__doc__)
68        i = i.parent
69
70def pytest_runtest_makereport(item, call):
71    if call.when == 'call' and call.excinfo is None:
72        _legacy_check_screenshots(item)
73        _commit_screenshots(item)
74
75def _legacy_check_screenshots(item):
76    # TODO: Remove after migrating all tests
77    if hasattr(item, 'obj') and hasattr(item.obj, '__self__'):
78        if hasattr(item.obj.__self__, 'check_screenshots'):
79            item.obj.__self__.check_screenshots()
80
81def _commit_screenshots(item):
82    if hasattr(item.session, 'pending_screenshots'):
83        for fixture in item.session.pending_screenshots:
84            fixture.commit_screenshots()
85
86