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
|
import os
import typing
from logging import NullHandler, getLogger
import yaml
try:
from importlib.resources import files
except ImportError:
from importlib_resources import files # type: ignore[assignment,no-redef,import-not-found]
from knowit.serializer import get_yaml_loader
logger = getLogger(__name__)
logger.addHandler(NullHandler())
class _Value(typing.NamedTuple):
code: str
default: str
human: str
technical: str
_valid_aliases = _Value._fields
class Config:
"""Application config class."""
@classmethod
def build(cls, path: typing.Optional[typing.Union[str, os.PathLike]] = None) -> 'Config':
"""Build config instance."""
loader = get_yaml_loader()
config_file = files(__package__).joinpath('defaults.yml')
with config_file.open('rb') as stream:
cfgs = [yaml.load(stream, Loader=loader)]
if path:
with open(path, 'rb') as stream:
cfgs.append(yaml.load(stream, Loader=loader))
profiles_data = {}
for cfg in cfgs:
if 'profiles' in cfg:
profiles_data.update(cfg['profiles'])
knowledge_data = {}
for cfg in cfgs:
if 'knowledge' in cfg:
knowledge_data.update(cfg['knowledge'])
data: typing.Dict[str, typing.MutableMapping] = {'general': {}}
for class_name, data_map in knowledge_data.items():
data.setdefault(class_name, {})
for code, detection_values in data_map.items():
alias_map = (profiles_data.get(class_name) or {}).get(code) or {}
alias_map.setdefault('code', code)
alias_map.setdefault('default', alias_map['code'])
alias_map.setdefault('human', alias_map['default'])
alias_map.setdefault('technical', alias_map['human'])
value = _Value(**{k: v for k, v in alias_map.items() if k in _valid_aliases})
for detection_value in detection_values:
data[class_name][str(detection_value)] = value
config = Config()
config.__dict__ = data
return config
|