1"""Configuration file for pytest."""
2import os
3import pytest
4import yaml
5import copy
6import abipy.flowtk as flowtk
7
8from monty.collections import AttrDict
9from monty.string import marquee
10
11# Are we running on travis?
12on_travis = os.environ.get("TRAVIS", "False") == "true"
13
14# Create the list of Manager configurations used for the integration tests.
15# Note that the items in _manager_confs must be hashable hence we cannot use dictionaries directly
16# To bypass this problem we operate on dictionaries to generate the different configuration
17# and then we convert the dictionary to string with yaml.dump. This string will be passed
18# to Manager.from_string in fwp. base_conf looks like:
19
20USER_CONFIG_DIR = os.path.join(os.path.expanduser("~"), ".abinit", "abipy")
21#USER_CONFIG_DIR = os.path.dirname(__file__)
22
23# Read the base configuration from file
24with open(os.path.join(USER_CONFIG_DIR, "manager.yml")) as fh:
25    base_conf = yaml.safe_load(fh)
26
27# Build list of configurations.
28_manager_confs = []
29
30for autoparal in [1]: #, 1]:
31    newd = copy.deepcopy(base_conf)
32    if "policy" not in newd: newd["policy"] = {}
33    newd["policy"]["autoparal"] = autoparal
34    _manager_confs.append(newd)
35
36_manager_confs = [yaml.dump(d) for d in _manager_confs]
37#_manager_confs = [base_conf]
38
39
40@pytest.fixture(params=_manager_confs)
41def fwp(tmpdir, request):
42    """
43    Parameters used to initialize Flows.
44
45    This fixture allows us to change the |TaskManager| so that we can easily test different configurations.
46    """
47    # Temporary working directory
48    fwp.workdir = str(tmpdir)
49
50    # Create the TaskManager.
51    fwp.manager = flowtk.TaskManager.from_string(request.param)
52    fwp.scheduler = flowtk.PyFlowScheduler.from_file(os.path.join(USER_CONFIG_DIR, "scheduler.yml"))
53    fwp.on_travis = on_travis
54    fwp.abinit_build = flowtk.AbinitBuild()
55
56    return fwp
57
58
59# Use tuples instead of dict because pytest require objects to be hashable.
60if on_travis:
61    _tvars_list = [
62        (("paral_kgb", 0),),
63        #(("paral_kgb", 1),),
64    ]
65
66else:
67    _tvars_list = [
68        #(("paral_kgb", 0),),
69        (("paral_kgb", 1),),
70    ]
71
72
73@pytest.fixture(params=_tvars_list)
74def tvars(request):
75    """
76    Abinit variables passed to the test functions.
77
78    This fixture allows us change the variables in the input files
79    so that we can easily test different scenarios e.g. runs with or without paral_kgb == 1
80    """
81    return AttrDict({k: v for k, v in request.param})
82
83
84def pytest_addoption(parser):
85    """Add extra command line options."""
86    parser.addoption('--loglevel', default="ERROR", type=str,
87                     help="Set the loglevel. Possible values: CRITICAL, ERROR (default), WARNING, INFO, DEBUG")
88    #parser.addoption('--manager', default=None, help="TaskManager file (defaults to the manager.yml found in cwd"
89
90
91def pytest_report_header(config):
92    """Write the initial header."""
93    lines = []
94    app = lines.append
95    app("\n" + marquee("Begin integration tests for AbiPy + abinit", mark="="))
96    app("\tAssuming the environment is properly configured:")
97    app("\tIn particular, the abinit executable must be in $PATH.")
98    app("\tChange manager.yml according to your platform.")
99    app("\tNumber of TaskManager configurations used: %d" % len(_manager_confs))
100
101    if config.option.verbose > 0:
102        for i, s in enumerate(_manager_confs):
103            app(80 * "=")
104            app("TaskManager #%d" % i)
105            app(s)
106            app(80 * "=")
107    app("")
108
109    # Print info on Abinit build
110    abinit_build = flowtk.AbinitBuild()
111    print()
112    print(abinit_build)
113    print()
114    if not config.option.verbose:
115        print("Use --verbose for additional info")
116    else:
117        print(abinit_build.info)
118
119    # Initialize logging
120    # loglevel is bound to the string value obtained from the command line argument.
121    # Convert to upper case to allow the user to specify --loglevel=DEBUG or --loglevel=debug
122    import logging
123    numeric_level = getattr(logging, config.option.loglevel.upper(), None)
124    if not isinstance(numeric_level, int):
125        raise ValueError('Invalid log level: %s' % config.option.loglevel)
126    logging.basicConfig(level=numeric_level)
127
128    return lines
129