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