Spaces:
				
			
			
	
			
			
		Runtime error
		
	
	
	
			
			
	
	
	
	
		
		
		Runtime error
		
	File size: 3,285 Bytes
			
			| 0a1b571 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 | import json
import os
from pathlib import Path
from typing import Any, Optional, TypeVar, overload
import confuse
import dotenv
from pydantic import parse_obj_as
from hibiapi import __file__ as root_file
CONFIG_DIR = Path(".") / "configs"
DEFAULT_DIR = Path(root_file).parent / "configs"
_T = TypeVar("_T")
class ConfigSubView(confuse.Subview):
    @overload
    def get(self) -> Any: ...
    @overload
    def get(self, template: type[_T]) -> _T: ...
    def get(self, template: Optional[type[_T]] = None):  # type: ignore
        object_ = super().get()
        if template is not None:
            return parse_obj_as(template, object_)
        return object_
    def get_optional(self, template: type[_T]) -> Optional[_T]:
        try:
            return self.get(template)
        except Exception:
            return None
    def as_str(self) -> str:
        return self.get(str)
    def as_str_seq(self, split: str = "\n") -> list[str]:  # type: ignore
        return [
            stripped
            for line in self.as_str().strip().split(split)
            if (stripped := line.strip())
        ]
    def as_number(self) -> int:
        return self.get(int)
    def as_bool(self) -> bool:
        return self.get(bool)
    def as_path(self) -> Path:
        return self.get(Path)
    def as_dict(self) -> dict[str, Any]:
        return self.get(dict[str, Any])
    def __getitem__(self, key: str) -> "ConfigSubView":
        return self.__class__(self, key)
class AppConfig(confuse.Configuration):
    def __init__(self, name: str):
        self._config_name = name
        self._config = CONFIG_DIR / (filename := f"{name}.yml")
        self._default = DEFAULT_DIR / filename
        super().__init__(name)
        self._add_env_source()
    def config_dir(self) -> str:
        return str(CONFIG_DIR)
    def user_config_path(self) -> str:
        return str(self._config)
    def _add_env_source(self):
        if dotenv.find_dotenv():
            dotenv.load_dotenv()
        config_name = f"{self._config_name.lower()}_"
        env_configs = {
            k[len(config_name) :].lower(): str(v)
            for k, v in os.environ.items()
            if k.lower().startswith(config_name)
        }
        # Convert `AAA_BBB_CCC=DDD` to `{'aaa':{'bbb':{'ccc':'ddd'}}}`
        source_tree: dict[str, Any] = {}
        for key, value in env_configs.items():
            _tmp = source_tree
            *nodes, name = key.split("_")
            for node in nodes:
                _tmp = _tmp.setdefault(node, {})
            if value == "":
                continue
            try:
                _tmp[name] = json.loads(value)
            except json.JSONDecodeError:
                _tmp[name] = value
        self.sources.insert(0, confuse.ConfigSource.of(source_tree))
    def _add_default_source(self):
        self.add(confuse.YamlSource(self._default, default=True))
    def _add_user_source(self):
        self.add(confuse.YamlSource(self._config, optional=True))
    def __getitem__(self, key: str) -> ConfigSubView:
        return ConfigSubView(self, key)
class GeneralConfig(AppConfig):
    def __init__(self, name: str):
        super().__init__(name)
class APIConfig(GeneralConfig):
    pass
Config = GeneralConfig("general")
 | 
 
			
