1import configparser 2import json 3import os 4 5conf = {} 6default_conf_dir = os.path.join(os.path.expanduser("~"), ".config/fsspec") 7conf_dir = os.environ.get("FSSPEC_CONFIG_DIR", default_conf_dir) 8 9 10def set_conf_env(conf_dict, envdict=os.environ): 11 """Set config values from environment variables 12 13 Looks for variable of the form ``FSSPEC_<protocol>_<kwarg>``. 14 There is no attempt to convert strings, but the kwarg keys will 15 be lower-cased. 16 17 Parameters 18 ---------- 19 conf_dict : dict(str, dict) 20 This dict will be mutated 21 envdict : dict-like(str, str) 22 Source for the values - usually the real environment 23 """ 24 for key in envdict: 25 if key.startswith("FSSPEC"): 26 if key.count("_") < 2: 27 continue 28 _, proto, kwarg = key.split("_", 2) 29 conf_dict.setdefault(proto.lower(), {})[kwarg.lower()] = envdict[key] 30 31 32def set_conf_files(cdir, conf_dict): 33 """Set config values from files 34 35 Scans for INI and JSON files in the given dictionary, and uses their 36 contents to set the config. In case of repeated values, later values 37 win. 38 39 In the case of INI files, all values are strings, and these will not 40 be converted. 41 42 Parameters 43 ---------- 44 cdir : str 45 Directory to search 46 conf_dict : dict(str, dict) 47 This dict will be mutated 48 """ 49 if not os.path.isdir(cdir): 50 return 51 allfiles = sorted(os.listdir(cdir)) 52 for fn in allfiles: 53 if fn.endswith(".ini"): 54 ini = configparser.ConfigParser() 55 ini.read(os.path.join(cdir, fn)) 56 for key in ini: 57 if key == "DEFAULT": 58 continue 59 conf_dict.setdefault(key, {}).update(dict(ini[key])) 60 if fn.endswith(".json"): 61 js = json.load(open(os.path.join(cdir, fn))) 62 for key in js: 63 conf_dict.setdefault(key, {}).update(dict(js[key])) 64 65 66def apply_config(cls, kwargs, conf_dict=None): 67 """Supply default values for kwargs when instantiating class 68 69 Augments the passed kwargs, by finding entries in the config dict 70 which match the classes ``.protocol`` attribute (one or more str) 71 72 Parameters 73 ---------- 74 cls : file system implementation 75 kwargs : dict 76 conf_dict : dict of dict 77 Typically this is the global configuration 78 79 Returns 80 ------- 81 dict : the modified set of kwargs 82 """ 83 if conf_dict is None: 84 conf_dict = conf 85 protos = cls.protocol if isinstance(cls.protocol, (tuple, list)) else [cls.protocol] 86 kw = {} 87 for proto in protos: 88 # default kwargs from the current state of the config 89 if proto in conf_dict: 90 kw.update(conf_dict[proto]) 91 # explicit kwargs always win 92 kw.update(**kwargs) 93 kwargs = kw 94 return kwargs 95 96 97set_conf_files(conf_dir, conf) 98set_conf_env(conf) 99