omlish 0.0.0.dev191__py3-none-any.whl → 0.0.0.dev193__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- omlish/.manifests.json +17 -3
- omlish/__about__.py +2 -2
- omlish/codecs/base.py +2 -0
- omlish/configs/__init__.py +0 -5
- omlish/configs/flattening.py +31 -33
- omlish/configs/strings.py +2 -2
- omlish/formats/__init__.py +5 -0
- omlish/formats/ini/__init__.py +0 -0
- omlish/formats/ini/codec.py +26 -0
- omlish/formats/ini/sections.py +45 -0
- omlish/formats/toml/__init__.py +0 -0
- omlish/formats/{toml.py → toml/codec.py} +2 -2
- omlish/formats/toml/parser.py +827 -0
- omlish/formats/toml/writer.py +115 -0
- omlish/lang/__init__.py +4 -1
- omlish/lang/iterables.py +0 -7
- omlish/lite/types.py +9 -0
- omlish/text/glyphsplit.py +12 -10
- {omlish-0.0.0.dev191.dist-info → omlish-0.0.0.dev193.dist-info}/METADATA +1 -1
- {omlish-0.0.0.dev191.dist-info → omlish-0.0.0.dev193.dist-info}/RECORD +24 -17
- {omlish-0.0.0.dev191.dist-info → omlish-0.0.0.dev193.dist-info}/LICENSE +0 -0
- {omlish-0.0.0.dev191.dist-info → omlish-0.0.0.dev193.dist-info}/WHEEL +0 -0
- {omlish-0.0.0.dev191.dist-info → omlish-0.0.0.dev193.dist-info}/entry_points.txt +0 -0
- {omlish-0.0.0.dev191.dist-info → omlish-0.0.0.dev193.dist-info}/top_level.txt +0 -0
omlish/.manifests.json
CHANGED
@@ -51,6 +51,20 @@
|
|
51
51
|
}
|
52
52
|
}
|
53
53
|
},
|
54
|
+
{
|
55
|
+
"module": ".formats.ini.codec",
|
56
|
+
"attr": "_INI_LAZY_CODEC",
|
57
|
+
"file": "omlish/formats/ini/codec.py",
|
58
|
+
"line": 25,
|
59
|
+
"value": {
|
60
|
+
"$.codecs.base.LazyLoadedCodec": {
|
61
|
+
"mod_name": "omlish.formats.ini.codec",
|
62
|
+
"attr_name": "INI_CODEC",
|
63
|
+
"name": "ini",
|
64
|
+
"aliases": null
|
65
|
+
}
|
66
|
+
}
|
67
|
+
},
|
54
68
|
{
|
55
69
|
"module": ".formats.json.codecs",
|
56
70
|
"attr": "_JSON_LAZY_CODEC",
|
@@ -136,13 +150,13 @@
|
|
136
150
|
}
|
137
151
|
},
|
138
152
|
{
|
139
|
-
"module": ".formats.toml",
|
153
|
+
"module": ".formats.toml.codec",
|
140
154
|
"attr": "_TOML_LAZY_CODEC",
|
141
|
-
"file": "omlish/formats/toml.py",
|
155
|
+
"file": "omlish/formats/toml/codec.py",
|
142
156
|
"line": 16,
|
143
157
|
"value": {
|
144
158
|
"$.codecs.base.LazyLoadedCodec": {
|
145
|
-
"mod_name": "omlish.formats.toml",
|
159
|
+
"mod_name": "omlish.formats.toml.codec",
|
146
160
|
"attr_name": "TOML_CODEC",
|
147
161
|
"name": "toml",
|
148
162
|
"aliases": null
|
omlish/__about__.py
CHANGED
omlish/codecs/base.py
CHANGED
omlish/configs/__init__.py
CHANGED
omlish/configs/flattening.py
CHANGED
@@ -1,32 +1,33 @@
|
|
1
|
+
# ruff: noqa: UP006 UP007
|
2
|
+
# @omlish-lite
|
1
3
|
import abc
|
2
|
-
import itertools
|
3
4
|
import typing as ta
|
4
5
|
|
5
|
-
from .. import check
|
6
|
-
from .. import lang
|
6
|
+
from ..lite.check import check
|
7
7
|
|
8
8
|
|
9
9
|
K = ta.TypeVar('K')
|
10
10
|
V = ta.TypeVar('V')
|
11
|
-
StrMap = ta.Mapping[str, ta.Any]
|
12
11
|
|
13
12
|
|
14
|
-
|
15
|
-
pass
|
13
|
+
##
|
16
14
|
|
17
15
|
|
18
|
-
class
|
19
|
-
|
16
|
+
class ConfigFlattening:
|
20
17
|
DEFAULT_DELIMITER = '.'
|
21
18
|
DEFAULT_INDEX_OPEN = '('
|
22
19
|
DEFAULT_INDEX_CLOSE = ')'
|
23
20
|
|
21
|
+
class _MISSING:
|
22
|
+
def __new__(cls, *args, **kwargs): # noqa
|
23
|
+
raise TypeError
|
24
|
+
|
24
25
|
def __init__(
|
25
26
|
self,
|
26
27
|
*,
|
27
|
-
delimiter=DEFAULT_DELIMITER,
|
28
|
-
index_open=DEFAULT_INDEX_OPEN,
|
29
|
-
index_close=DEFAULT_INDEX_CLOSE,
|
28
|
+
delimiter: str = DEFAULT_DELIMITER,
|
29
|
+
index_open: str = DEFAULT_INDEX_OPEN,
|
30
|
+
index_close: str = DEFAULT_INDEX_CLOSE,
|
30
31
|
) -> None:
|
31
32
|
super().__init__()
|
32
33
|
|
@@ -34,8 +35,8 @@ class Flattening:
|
|
34
35
|
self._index_open = check.not_empty(index_open)
|
35
36
|
self._index_close = check.not_empty(index_close)
|
36
37
|
|
37
|
-
def flatten(self, unflattened:
|
38
|
-
def rec(prefix:
|
38
|
+
def flatten(self, unflattened: ta.Mapping[str, ta.Any]) -> ta.Mapping[str, ta.Any]:
|
39
|
+
def rec(prefix: ta.List[str], value: ta.Any) -> None:
|
39
40
|
if isinstance(value, dict):
|
40
41
|
for k, v in value.items():
|
41
42
|
rec([*prefix, k], v)
|
@@ -53,8 +54,7 @@ class Flattening:
|
|
53
54
|
rec([], unflattened)
|
54
55
|
return ret
|
55
56
|
|
56
|
-
class UnflattenNode(
|
57
|
-
|
57
|
+
class UnflattenNode(abc.ABC, ta.Generic[K]):
|
58
58
|
@abc.abstractmethod
|
59
59
|
def get(self, key: K) -> ta.Any:
|
60
60
|
raise NotImplementedError
|
@@ -65,7 +65,7 @@ class Flattening:
|
|
65
65
|
|
66
66
|
def setdefault(self, key: K, supplier: ta.Callable[[], V]) -> V:
|
67
67
|
ret = self.get(key)
|
68
|
-
if ret is _MISSING:
|
68
|
+
if ret is ConfigFlattening._MISSING:
|
69
69
|
ret = supplier()
|
70
70
|
self.put(key, ret)
|
71
71
|
return ret
|
@@ -77,50 +77,48 @@ class Flattening:
|
|
77
77
|
@staticmethod
|
78
78
|
def maybe_build(value: ta.Any) -> ta.Any:
|
79
79
|
check.not_none(value)
|
80
|
-
return value.build() if isinstance(value,
|
80
|
+
return value.build() if isinstance(value, ConfigFlattening.UnflattenNode) else value
|
81
81
|
|
82
82
|
class UnflattenDict(UnflattenNode[str]):
|
83
|
-
|
84
83
|
def __init__(self) -> None:
|
85
84
|
super().__init__()
|
86
85
|
|
87
86
|
self._dict: dict[str, ta.Any] = {}
|
88
87
|
|
89
88
|
def get(self, key: str) -> ta.Any:
|
90
|
-
return self._dict.get(key, _MISSING)
|
89
|
+
return self._dict.get(key, ConfigFlattening._MISSING)
|
91
90
|
|
92
91
|
def put(self, key: str, value: ta.Any) -> None:
|
93
92
|
check.arg(key not in self._dict)
|
94
93
|
self._dict[key] = value
|
95
94
|
|
96
95
|
def build(self) -> ta.Any:
|
97
|
-
return {k:
|
96
|
+
return {k: ConfigFlattening.UnflattenNode.maybe_build(v) for k, v in self._dict.items()}
|
98
97
|
|
99
98
|
class UnflattenList(UnflattenNode[int]):
|
100
|
-
|
101
99
|
def __init__(self) -> None:
|
102
100
|
super().__init__()
|
103
101
|
|
104
|
-
self._list:
|
102
|
+
self._list: ta.List[ta.Any] = []
|
105
103
|
|
106
104
|
def get(self, key: int) -> ta.Any:
|
107
105
|
check.arg(key >= 0)
|
108
|
-
return self._list[key] if key < len(self._list) else _MISSING
|
106
|
+
return self._list[key] if key < len(self._list) else ConfigFlattening._MISSING
|
109
107
|
|
110
108
|
def put(self, key: int, value: ta.Any) -> None:
|
111
109
|
check.arg(key >= 0)
|
112
110
|
if key >= len(self._list):
|
113
|
-
self._list.extend([_MISSING] * (key - len(self._list) + 1))
|
114
|
-
check.arg(self._list[key] is _MISSING)
|
111
|
+
self._list.extend([ConfigFlattening._MISSING] * (key - len(self._list) + 1))
|
112
|
+
check.arg(self._list[key] is ConfigFlattening._MISSING)
|
115
113
|
self._list[key] = value
|
116
114
|
|
117
115
|
def build(self) -> ta.Any:
|
118
|
-
return [
|
116
|
+
return [ConfigFlattening.UnflattenNode.maybe_build(e) for e in self._list]
|
119
117
|
|
120
|
-
def unflatten(self, flattened:
|
121
|
-
root =
|
118
|
+
def unflatten(self, flattened: ta.Mapping[str, ta.Any]) -> ta.Mapping[str, ta.Any]:
|
119
|
+
root = ConfigFlattening.UnflattenDict()
|
122
120
|
|
123
|
-
def split_keys(fkey: str) -> ta.Iterable[str
|
121
|
+
def split_keys(fkey: str) -> ta.Iterable[ta.Union[str, int]]:
|
124
122
|
for part in fkey.split(self._delimiter):
|
125
123
|
if self._index_open in part:
|
126
124
|
check.state(part.endswith(self._index_close))
|
@@ -134,13 +132,13 @@ class Flattening:
|
|
134
132
|
yield part
|
135
133
|
|
136
134
|
for fk, v in flattened.items():
|
137
|
-
node:
|
135
|
+
node: ConfigFlattening.UnflattenNode = root
|
138
136
|
fks = list(split_keys(fk))
|
139
|
-
for key, nkey in
|
137
|
+
for key, nkey in zip(fks, fks[1:]): # noqa
|
140
138
|
if isinstance(nkey, str):
|
141
|
-
node = node.setdefault(key,
|
139
|
+
node = node.setdefault(key, ConfigFlattening.UnflattenDict)
|
142
140
|
elif isinstance(nkey, int):
|
143
|
-
node = node.setdefault(key,
|
141
|
+
node = node.setdefault(key, ConfigFlattening.UnflattenList)
|
144
142
|
else:
|
145
143
|
raise TypeError(key)
|
146
144
|
node.put(fks[-1], v)
|
omlish/configs/strings.py
CHANGED
@@ -88,9 +88,9 @@ def interpolate_strings(v: T, rpl: ta.Mapping[str, str]) -> T:
|
|
88
88
|
def fn(v):
|
89
89
|
if not v:
|
90
90
|
return v
|
91
|
-
sps = glyphsplit.
|
91
|
+
sps = glyphsplit.glyph_split_braces(v)
|
92
92
|
if len(sps) == 1 and isinstance(sps[0], str):
|
93
93
|
return sps[0]
|
94
|
-
return ''.join(rpl[p.s] if isinstance(p, glyphsplit.
|
94
|
+
return ''.join(rpl[p.s] if isinstance(p, glyphsplit.GlyphSplitMatch) else p for p in sps)
|
95
95
|
|
96
96
|
return StringRewriter(fn)(v)
|
File without changes
|
@@ -0,0 +1,26 @@
|
|
1
|
+
import configparser
|
2
|
+
|
3
|
+
from ..codecs import make_object_lazy_loaded_codec
|
4
|
+
from ..codecs import make_str_object_codec
|
5
|
+
from .sections import IniSectionSettingsMap
|
6
|
+
from .sections import extract_ini_sections
|
7
|
+
from .sections import render_ini_sections
|
8
|
+
|
9
|
+
|
10
|
+
##
|
11
|
+
|
12
|
+
|
13
|
+
def loads(s: str) -> IniSectionSettingsMap:
|
14
|
+
cp = configparser.ConfigParser()
|
15
|
+
cp.read_string(s)
|
16
|
+
return extract_ini_sections(cp)
|
17
|
+
|
18
|
+
|
19
|
+
def dumps(sm: IniSectionSettingsMap) -> str:
|
20
|
+
return render_ini_sections(sm)
|
21
|
+
|
22
|
+
|
23
|
+
INI_CODEC = make_str_object_codec('ini', dumps, loads)
|
24
|
+
|
25
|
+
# @omlish-manifest
|
26
|
+
_INI_LAZY_CODEC = make_object_lazy_loaded_codec(__name__, 'INI_CODEC', INI_CODEC)
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# ruff: noqa: UP006 UP007
|
2
|
+
# @omlish-lite
|
3
|
+
import configparser
|
4
|
+
import io
|
5
|
+
import typing as ta
|
6
|
+
|
7
|
+
|
8
|
+
IniSectionSettingsMap = ta.Mapping[str, ta.Mapping[str, ta.Union[str, ta.Sequence[str]]]] # ta.TypeAlias
|
9
|
+
|
10
|
+
|
11
|
+
##
|
12
|
+
|
13
|
+
|
14
|
+
def extract_ini_sections(cp: configparser.ConfigParser) -> IniSectionSettingsMap:
|
15
|
+
config_dct: ta.Dict[str, ta.Any] = {}
|
16
|
+
for sec in cp.sections():
|
17
|
+
cd = config_dct
|
18
|
+
for k in sec.split('.'):
|
19
|
+
cd = cd.setdefault(k, {})
|
20
|
+
cd.update(cp.items(sec))
|
21
|
+
return config_dct
|
22
|
+
|
23
|
+
|
24
|
+
##
|
25
|
+
|
26
|
+
|
27
|
+
def render_ini_sections(
|
28
|
+
settings_by_section: IniSectionSettingsMap,
|
29
|
+
) -> str:
|
30
|
+
out = io.StringIO()
|
31
|
+
|
32
|
+
for i, (section, settings) in enumerate(settings_by_section.items()):
|
33
|
+
if i:
|
34
|
+
out.write('\n')
|
35
|
+
|
36
|
+
out.write(f'[{section}]\n')
|
37
|
+
|
38
|
+
for k, v in settings.items():
|
39
|
+
if isinstance(v, str):
|
40
|
+
out.write(f'{k}={v}\n')
|
41
|
+
else:
|
42
|
+
for vv in v:
|
43
|
+
out.write(f'{k}={vv}\n')
|
44
|
+
|
45
|
+
return out.getvalue()
|
File without changes
|