File size: 2,943 Bytes
f6ff4fa
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import json
import os

from dotenv import load_dotenv
from dotenv.main import DotEnv

from toolbox.json.misc import traverse


class EnvironmentManager(object):
    def __init__(self, path, env, override=False):
        filename = os.path.join(path, '{}.env'.format(env))
        self.filename = filename

        load_dotenv(
            dotenv_path=filename,
            override=override
        )

        self._environ = dict()

    def open_dotenv(self, filename: str = None):
        filename = filename or self.filename
        dotenv = DotEnv(
            dotenv_path=filename,
            stream=None,
            verbose=False,
            interpolate=False,
            override=False,
            encoding="utf-8",
        )
        result = dotenv.dict()
        return result

    def get(self, key, default=None, dtype=str):
        result = os.environ.get(key)
        if result is None:
            if default is None:
                result = None
            else:
                result = default
        else:
            result = dtype(result)
        self._environ[key] = result
        return result


_DEFAULT_DTYPE_MAP = {
    'int': int,
    'float': float,
    'str': str,
    'json.loads': json.loads
}


class JsonConfig(object):
    """
    将 json 中, 形如 `$float:threshold` 的值, 处理为:
    从环境变量中查到 threshold, 再将其转换为 float 类型.
    """
    def __init__(self, dtype_map: dict = None, environment: EnvironmentManager = None):
        self.dtype_map = dtype_map or _DEFAULT_DTYPE_MAP
        self.environment = environment or os.environ

    def sanitize_by_filename(self, filename: str):
        with open(filename, 'r', encoding='utf-8') as f:
            js = json.load(f)

        return self.sanitize_by_json(js)

    def sanitize_by_json(self, js):
        js = traverse(
            js,
            callback=self.sanitize,
            environment=self.environment
        )
        return js

    def sanitize(self, string, environment):
        """支持 $ 符开始的, 环境变量配置"""
        if isinstance(string, str) and string.startswith('$'):
            dtype, key = string[1:].split(':')
            dtype = self.dtype_map[dtype]

            value = environment.get(key)
            if value is None:
                raise AssertionError('environment not exist. key: {}'.format(key))

            value = dtype(value)
            result = value
        else:
            result = string
        return result


def demo1():
    import json

    from project_settings import project_path

    environment = EnvironmentManager(
        path=os.path.join(project_path, 'server/callbot_server/dotenv'),
        env='dev',
    )
    init_scenes = environment.get(key='init_scenes', dtype=json.loads)
    print(init_scenes)
    print(environment._environ)
    return


if __name__ == '__main__':
    demo1()