1""" 2Find directories 3""" 4import importlib 5import os 6import sys 7from typing import Any 8from typing import Dict 9from typing import Iterable 10from typing import List 11 12import dict_tools.update 13 14 15def dir_list( 16 subname: str, p_name: str, pypath: List[str] = None, static: List[str] = None 17) -> List[str]: 18 """ 19 Return the directories to look for modules in, pypath specifies files 20 relative to an installed python package, static is for static dirs 21 :param subname: ignored 22 :param p_name: ignored 23 :param pypath: One or many python paths which will be imported 24 :param static: Directories that can be explicitly passed 25 """ 26 ret = [] 27 for path in pypath: 28 mod = importlib.import_module(path) 29 for m_path in mod.__path__: 30 # If we are inside of an executable the path will be different 31 ret.append(m_path) 32 ret.extend(static) 33 return ret 34 35 36def inline_dirs(dirs: Iterable[str], subdir: str) -> List[str]: 37 """ 38 Look for the named subdir in the list of dirs 39 :param dirs: The names of configured dynamic dirs 40 :param subdir: The name of the subdir to check for in the list of dynamic dirs 41 :return An extended list of dirs that includes the found subdirs 42 """ 43 ret = [] 44 for dir_ in dirs: 45 check = os.path.join(dir_, subdir) 46 if os.path.isdir(check): 47 ret.append(check) 48 return ret 49 50 51def dynamic_dirs() -> Dict[str, Any]: 52 """ 53 Iterate over the available python package imports and look for configured 54 dynamic dirs 55 """ 56 dirs = [] 57 ret = {} 58 for dir_ in sys.path: 59 if not os.path.isdir(dir_): 60 continue 61 for sub in os.listdir(dir_): 62 full = os.path.join(dir_, sub) 63 if full.endswith(".egg-link"): 64 with open(full) as rfh: 65 dirs.append(rfh.read().strip()) 66 if os.path.isdir(full): 67 dirs.append(full) 68 for dir_ in dirs: 69 conf = os.path.join(dir_, "conf.py") 70 context = {} 71 if not os.path.isfile(conf): 72 continue 73 try: 74 with open(conf) as f: 75 code = f.read() 76 if "DYNE" in code: 77 exec(code, context) 78 else: 79 continue 80 except Exception: 81 continue 82 if "DYNE" in context: 83 if not isinstance(context["DYNE"], dict): 84 continue 85 for name, paths in context["DYNE"].items(): 86 if not isinstance(paths, list): 87 continue 88 if name not in ret: 89 ret[name] = { 90 "paths": [], 91 "CONFIG": {}, 92 "CLI_CONFIG": {}, 93 "SUBCOMMANDS": {}, 94 } 95 if "CONFIG" in context: 96 dict_tools.update.update(ret[name]["CONFIG"], context["CONFIG"]) 97 if "CLI_CONFIG" in context: 98 dict_tools.update.update( 99 ret[name]["CLI_CONFIG"], context["CLI_CONFIG"] 100 ) 101 if "SUBCOMMANDS" in context: 102 dict_tools.update.update( 103 ret[name]["SUBCOMMANDS"], context["SUBCOMMANDS"] 104 ) 105 for path in paths: 106 ref = os.path.join(dir_, path.replace(".", os.sep)) 107 if dir_.endswith(name): 108 ret[name]["paths"].insert(0, ref) 109 else: 110 ret[name]["paths"].append(ref) 111 for name in ret: 112 if not ret[name]: 113 continue 114 first = ret[name]["paths"].pop(0) 115 ret[name]["paths"] = sorted(ret[name]["paths"]) 116 ret[name]["paths"].insert(0, first) 117 return ret 118