Source code for expyre.config

"""configuration for expyre from ``config.json``. Use env var ``EXPYRE_ROOT`` if set.
Otherwise (or if env var is set to ``@``), search from ``HOME`` (or ``/``, if current
dir is not below ``HOME``) down to current directory for ``.expyre`` or ``_expyre``.
Configuration is parsed in the same order, with deeper directories modifying previous
ones.  ``local_stage_dir`` is set to deepest directory unless it is set explicitly
in one of the found ``config.json`` files.

Global variables
----------------

local_stage_dir: str
    path of directory to stage jobs into
systems: dict
    dict of expyre.system.System that jobs can run on
db: JobsDB
    expyre.jobsdb.JobsDB database of jobs
"""
import sys
import os
import json
from pathlib import Path

from copy import deepcopy

[docs]def update_dict_leaves(d, d_loc): for k_loc, v_loc in d_loc.items(): if v_loc == "_DELETE_" and k_loc in d: del d[k_loc] elif k_loc not in d: # create new d[k_loc] = deepcopy(v_loc) else: # override if isinstance(v_loc, dict): # dict, override leaves inside assert isinstance(d[k_loc], dict) update_dict_leaves(d[k_loc], v_loc) else: # not dict, overwrite d[k_loc] = deepcopy(v_loc)
# read config.json file from expyre root (~/.expyre or EXPYRE_ROOT), # and save important parts (root, systems, db) as symbols in this module def _get_config(root_dir, verbose=False): """get configuration from root dir """ if root_dir == "@": if verbose: print("Searching directories") # search the path dirs = [] cur_dir = Path.cwd() while True: if (cur_dir / ".expyre").exists(): if (cur_dir / "_expyre").exists(): raise RuntimeError(f"Found both .expyre and _expyre in {cur_dir}") dirs.append(cur_dir / ".expyre") elif (cur_dir / "_expyre").exists(): if (cur_dir / ".expyre").exists(): raise RuntimeError(f"Found both .expyre and _expyre in {cur_dir}") dirs.append(cur_dir / "_expyre") if cur_dir.parent == cur_dir or cur_dir.absolute() == Path.home().absolute(): # reached ~ or / break cur_dir = cur_dir.parent dirs = list(reversed(dirs)) else: if verbose: print("Exact directory", root_dir) root_dir = Path(root_dir) if not root_dir.is_dir(): raise ValueError(f"expyre root {root_dir} is not a dir") dirs = [root_dir] if verbose: print("Using directories", dirs) config_data = {} for cur_dir in dirs: if verbose: print(f"Updating dict checking {cur_dir}") if (cur_dir / "config.json").exists(): with open(cur_dir / "config.json") as fin: d_loc = json.load(fin) update_dict_leaves(config_data, d_loc) if len(config_data) == 0: raise FileNotFoundError('Failed to find any config.json file') # use explicitly specified local_stage_dir, otherwise deepest config dir local_stage_dir = Path(config_data.get("local_stage_dir", dirs[-1])) return local_stage_dir, config_data local_stage_dir = None systems = None db = None
[docs]def init(root_dir, verbose=False): """Initializes ``root``, ``systems``, ``db``""" import os from .units import time_to_sec, mem_to_kB from .system import System from .jobsdb import JobsDB global local_stage_dir, systems, db try: local_stage_dir, _config_data = _get_config(root_dir, verbose=verbose) except FileNotFoundError: local_stage_dir = None systems = {} db = None return if local_stage_dir.name == '.expyre' or local_stage_dir.name == '_expyre': use_local_stage_dir = local_stage_dir.parent else: use_local_stage_dir = local_stage_dir _rundir_extra = os.environ.get('HOSTNAME', 'unkownhost') + '-' + str(use_local_stage_dir).replace('/', '_') systems = {} for _sys_name in _config_data['systems']: _sys_data = _config_data['systems'][_sys_name] if 'queues' in _sys_data: if 'partitions' in _sys_data: raise ValueError("config systems data contains both partitions and queues") _sys_data['partitions'] = _sys_data.pop('queues') if _sys_data['partitions'] is not None: for _partitions in _sys_data['partitions']: _sys_data['partitions'][_partitions]['max_time'] = time_to_sec(_sys_data['partitions'][_partitions]['max_time']) _sys_data['partitions'][_partitions]['max_mem'] = mem_to_kB(_sys_data['partitions'][_partitions]['max_mem']) systems[_sys_name] = System(rundir_extra=_rundir_extra, **_sys_data) db = JobsDB(local_stage_dir / 'jobs.db') if verbose: sys.stderr.write(f'expyre config got systems {list(systems.keys())}\n')
if 'pytest' not in sys.modules: init(os.environ.get("EXPYRE_ROOT", "@"))