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
|
import toml
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:
dirname = join(os.environ['HOME'], '.config', name)
filename = join(os.environ['HOME'], '.config', f'{name}.toml')
if isdir(dirname):
return join(dirname, 'config.toml')
elif isfile(filename):
return filename
else:
raise IOError(f'configuration file not found (tried {dirname}/config.toml and {filename})')
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)
self.data = {} if no_config else toml.load(path)
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)
|