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
|
import dataclasses as dc
import io
import os
from collections.abc import Generator, Iterator
from configparser import ConfigParser, MissingSectionHeaderError
from pathlib import Path
from typing import Any
GLOBAL_NAME = "xyz"
def config_parser_load(filename: str | Path) -> tuple[ConfigParser, bool]:
path = Path(filename)
config = ConfigParser()
try:
is_new = config.read(path)
return config, not bool(is_new)
except MissingSectionHeaderError:
text = path.read_text()
config.read_string(f"[{GLOBAL_NAME}]\n{text}")
return config, False
@dc.dataclass
class IniFile:
filename: str
is_new: bool = False
def __post_init__(self) -> None:
self.filename = os.path.abspath(self.filename)
self.config, self.is_new = config_parser_load(self.filename)
def __iter__(self) -> Iterator[str]:
if GLOBAL_NAME in self.config:
for option in self.config[GLOBAL_NAME]:
yield option
for section in self.config:
if section in {GLOBAL_NAME, "DEFAULT"}:
continue
for option in self.config[section]:
yield f"{section}.{option}"
def get(self, name: str, default: Any = None) -> Any:
section, _, option = name.rpartition(".")
while section.endswith("."):
section, option = section[:-1], f".{option}"
if not section:
return self.config[GLOBAL_NAME].get(option, default)
if section not in self.sections():
return default
return self.config[section].get(option, default)
def items(self) -> Generator[tuple[str, Any], None, None]:
for key in self:
yield key, self.get(key)
def __getitem__(self, name: str) -> Any:
return self.get(name)
def __setitem__(self, name: str, value: Any) -> None:
section, _, option = name.rpartition(".")
if not section:
self.config[GLOBAL_NAME][option] = value
return
if section not in self.sections():
self.config.add_section(section)
self.config[section][option] = value
def sections(self) -> list[str]:
return self.config.sections()
def section_as_dict(self, name: str) -> dict[str, Any]:
result = {}
for section in self.sections():
if section != name:
continue
for option in self.config[section]:
result[option] = self.config[section][option]
return result
def get_int(self, name: str, default: Any = None) -> int | None:
value = self.get(name, default)
if value is None:
return None
return int(value)
def get_bool(self, name: str, default: Any = False) -> bool | None:
value = self.get(name)
if value is None:
return None
return bool(
{
"0": False,
"no": False,
"false": False,
"1": True,
"yes": True,
"true": True,
}.get(value, default)
)
def save(self, create_folder=False) -> None:
raise NotImplementedError("not ready")
buffer = io.StringIO()
self.config.write(buffer)
with open(self.filename, "w") as fp:
fp.write(buffer.getvalue())
|