summaryrefslogtreecommitdiff
path: root/src/home/config/config.py
blob: af1c7727659e9000cfaf9e7ef8671ecf5a4ae84c (plain)
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
123
124
125
126
127
128
129
130
131
132
import toml
import yaml
import logging
import os

from os.path import join, isdir, isfile
from typing import Optional, Any, MutableMapping
from argparse import ArgumentParser


def _get_config_path(name: str) -> str:
    formats = ['toml', 'yaml']

    dirname = join(os.environ['HOME'], '.config', name)

    if isdir(dirname):
        for fmt in formats:
            filename = join(dirname, f'config.{fmt}')
            if isfile(filename):
                return filename

        raise IOError(f'config not found in {dirname}')

    else:
        filenames = [join(os.environ['HOME'], '.config', f'{name}.{format}') for format in formats]
        for file in filenames:
            if isfile(file):
                return file

    raise IOError(f'config not found')


class ConfigStore:
    data: MutableMapping[str, Any]
    app_name: Optional[str]

    def __int__(self):
        self.data = {}
        self.app_name = None

    def load(self, name: Optional[str] = None,
             use_cli=True,
             parser: ArgumentParser = None):
        self.app_name = name

        if (name is None) and (not use_cli):
            raise RuntimeError('either config name must be none or use_cli must be True')

        log_default_fmt = False
        log_file = None
        log_verbose = False
        no_config = name is False

        path = None
        if use_cli:
            if parser is None:
                parser = ArgumentParser()
            if not no_config:
                parser.add_argument('-c', '--config', type=str, required=name is None,
                                    help='Path to the config in TOML format')
            parser.add_argument('-V', '--verbose', action='store_true')
            parser.add_argument('--log-file', type=str)
            parser.add_argument('--log-default-fmt', action='store_true')
            args = parser.parse_args()

            if not no_config and args.config:
                path = args.config

            if args.verbose:
                log_verbose = True
            if args.log_file:
                log_file = args.log_file
            if args.log_default_fmt:
                log_default_fmt = args.log_default_fmt

        if not no_config and path is None:
            path = _get_config_path(name)

        if no_config:
            self.data = {}
        else:
            if path.endswith('.toml'):
                self.data = toml.load(path)
            elif path.endswith('.yaml'):
                with open(path, 'r') as fd:
                    self.data = yaml.safe_load(fd)

        if 'logging' in self:
            if not log_file and 'file' in self['logging']:
                log_file = self['logging']['file']
            if log_default_fmt and 'default_fmt' in self['logging']:
                log_default_fmt = self['logging']['default_fmt']

        setup_logging(log_verbose, log_file, log_default_fmt)

        if use_cli:
            return args

    def __getitem__(self, key):
        return self.data[key]

    def __setitem__(self, key, value):
        raise NotImplementedError('overwriting config values is prohibited')

    def __contains__(self, key):
        return key in self.data


config = ConfigStore()


def is_development_mode() -> bool:
    if 'FLASK_ENV' in os.environ and os.environ['FLASK_ENV'] == 'development':
        return True

    return ('logging' in config) and ('verbose' in config['logging']) and (config['logging']['verbose'] is True)


def setup_logging(verbose=False, log_file=None, default_fmt=False):
    logging_level = logging.INFO
    if is_development_mode() or verbose:
        logging_level = logging.DEBUG

    log_config = {'level': logging_level}
    if not default_fmt:
        log_config['format'] = '%(asctime)s - %(name)s - %(levelname)s - %(message)s'

    if log_file is not None:
        log_config['filename'] = log_file
        log_config['encoding'] = 'utf-8'

    logging.basicConfig(**log_config)