start adding Config
[utils.git] / src / budget_sync / config.py
1 import toml
2 import sys
3 from typing import Set, Dict, Any
4
5
6 class ConfigParseError(Exception):
7 pass
8
9
10 class Person:
11 def __init__(self, config: "Config", identifier: str):
12 self.config = config
13 self.identifier = identifier
14
15 def __eq__(self, other):
16 return self.identifier == other.identifier
17
18 def __hash__(self):
19 return hash(self.identifier)
20
21 def __repr__(self):
22 return f"Person(config=..., identifier={self.identifier!r})"
23
24
25 class Config:
26 def __init__(self, bugzilla_url: str, people: Dict[str, Person], aliases: Dict[str, Person] = None):
27 self.bugzilla_url = bugzilla_url
28 self.people = people
29 if aliases is None:
30 aliases = {}
31 for i in people:
32 aliases[i.identifier] = i
33 self.aliases = aliases
34
35 def __repr__(self):
36 return f"Config(bugzilla_url={self.bugzilla_url!r}, " \
37 f"people={self.people!r}, aliases={self.aliases!r})"
38
39 @staticmethod
40 def _parse_people(people: Any) -> Dict[str, Person]:
41 raise NotImplementedError()
42
43 @staticmethod
44 def _parse_aliases(people: Dict[str, Person], aliases: Any) -> Dict[str, Person]:
45 if not isinstance(aliases, dict):
46 raise ConfigParseError("`aliases` entry must be a table")
47 retval = {}
48 raise NotImplementedError()
49 return retval
50
51 @staticmethod
52 def _from_toml(parsed_toml: Dict[str, Any]) -> "Config":
53 people = None
54 aliases = None
55 bugzilla_url = None
56 for k, v in parsed_toml.items():
57 if k == "people":
58 people = Config._parse_people(v)
59 elif k == "aliases":
60 aliases = v
61 elif k == "bugzilla_url":
62 if not isinstance(v, str):
63 raise ConfigParseError("`bugzilla_url` must be a string")
64 bugzilla_url = v
65 else:
66 raise ConfigParseError(f"unknown config entry: `{k}`")
67
68 if people is None:
69 raise ConfigParseError("`people` key is missing")
70
71 if bugzilla_url is None:
72 raise ConfigParseError("`bugzilla_url` key is missing")
73
74 if aliases is not None:
75 aliases = Config._parse_aliases(people, aliases)
76
77 return Config(bugzilla_url=bugzilla_url,
78 people=people,
79 aliases=aliases)
80
81 @staticmethod
82 def from_str(text: str) -> "Config":
83 try:
84 parsed_toml = toml.loads(text)
85 except toml.TomlDecodeError as e:
86 new_err = ConfigParseError(f"TOML parse error: {e}")
87 raise new_err.with_traceback(sys.exc_info()[2])
88 return Config._from_toml(parsed_toml)
89
90 @staticmethod
91 def from_file(file: Any) -> "Config":
92 if isinstance(file, list):
93 raise TypeError("list is not a valid file or path")
94 try:
95 parsed_toml = toml.load(file)
96 except toml.TomlDecodeError as e:
97 new_err = ConfigParseError(f"TOML parse error: {e}")
98 raise new_err.with_traceback(sys.exc_info()[2])
99 return Config._from_toml(parsed_toml)