omlish 0.0.0.dev192__py3-none-any.whl → 0.0.0.dev194__py3-none-any.whl
Sign up to get free protection for your applications and to get access to all the features.
- omlish/.manifests.json +17 -3
- omlish/__about__.py +2 -2
- omlish/codecs/base.py +2 -0
- omlish/configs/__init__.py +0 -5
- omlish/configs/formats.py +247 -0
- omlish/configs/nginx.py +72 -0
- omlish/configs/processing/__init__.py +0 -0
- omlish/configs/{flattening.py → processing/flattening.py} +31 -33
- omlish/configs/processing/inheritance.py +58 -0
- omlish/configs/processing/matching.py +53 -0
- omlish/configs/processing/names.py +50 -0
- omlish/configs/processing/rewriting.py +141 -0
- omlish/configs/processing/strings.py +45 -0
- omlish/configs/types.py +9 -0
- omlish/formats/__init__.py +4 -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 +124 -0
- omlish/lang/__init__.py +4 -1
- omlish/lang/iterables.py +0 -7
- omlish/lite/configs.py +38 -0
- omlish/lite/types.py +9 -0
- omlish/text/glyphsplit.py +25 -10
- {omlish-0.0.0.dev192.dist-info → omlish-0.0.0.dev194.dist-info}/METADATA +1 -1
- {omlish-0.0.0.dev192.dist-info → omlish-0.0.0.dev194.dist-info}/RECORD +33 -17
- omlish/configs/strings.py +0 -96
- {omlish-0.0.0.dev192.dist-info → omlish-0.0.0.dev194.dist-info}/LICENSE +0 -0
- {omlish-0.0.0.dev192.dist-info → omlish-0.0.0.dev194.dist-info}/WHEEL +0 -0
- {omlish-0.0.0.dev192.dist-info → omlish-0.0.0.dev194.dist-info}/entry_points.txt +0 -0
- {omlish-0.0.0.dev192.dist-info → omlish-0.0.0.dev194.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,141 @@
|
|
1
|
+
# ruff: noqa: UP006 UP007
|
2
|
+
# @omlish-lite
|
3
|
+
import abc
|
4
|
+
import collections.abc
|
5
|
+
import dataclasses as dc
|
6
|
+
import typing as ta
|
7
|
+
|
8
|
+
from ...lite.check import check
|
9
|
+
from ...lite.types import BUILTIN_SCALAR_ITERABLE_TYPES
|
10
|
+
|
11
|
+
|
12
|
+
T = ta.TypeVar('T')
|
13
|
+
StrT = ta.TypeVar('StrT', bound=str)
|
14
|
+
MappingT = ta.TypeVar('MappingT', bound=ta.Mapping)
|
15
|
+
IterableT = ta.TypeVar('IterableT', bound=ta.Iterable)
|
16
|
+
|
17
|
+
ConfigRewriterItem = ta.Union[int, str, None] # ta.TypeAlias
|
18
|
+
ConfigRewriterPath = ta.Tuple[ConfigRewriterItem, ...] # ta.TypeAlias
|
19
|
+
|
20
|
+
|
21
|
+
##
|
22
|
+
|
23
|
+
|
24
|
+
class RawConfigMetadata:
|
25
|
+
def __new__(cls, *args, **kwargs): # noqa
|
26
|
+
raise TypeError
|
27
|
+
|
28
|
+
|
29
|
+
class ConfigRewriter(abc.ABC): # noqa
|
30
|
+
@dc.dataclass(frozen=True)
|
31
|
+
class Context(ta.Generic[T]):
|
32
|
+
obj: T
|
33
|
+
|
34
|
+
parent: ta.Optional['ConfigRewriter.Context'] = None
|
35
|
+
item: ConfigRewriterItem = None
|
36
|
+
|
37
|
+
raw: bool = False
|
38
|
+
|
39
|
+
def __post_init__(self) -> None:
|
40
|
+
if self.parent is None:
|
41
|
+
check.none(self.item)
|
42
|
+
|
43
|
+
@property
|
44
|
+
def path(self) -> ConfigRewriterPath:
|
45
|
+
cur: ConfigRewriter.Context = self
|
46
|
+
lst: ta.List[ConfigRewriterItem] = []
|
47
|
+
while True:
|
48
|
+
if cur.parent is None:
|
49
|
+
break
|
50
|
+
lst.append(cur.item)
|
51
|
+
cur = cur.parent
|
52
|
+
return tuple(reversed(lst))
|
53
|
+
|
54
|
+
def make_child(
|
55
|
+
self,
|
56
|
+
obj: ta.Any,
|
57
|
+
item: ConfigRewriterItem,
|
58
|
+
**kwargs: ta.Any,
|
59
|
+
) -> 'ConfigRewriter.Context':
|
60
|
+
return dc.replace(
|
61
|
+
self,
|
62
|
+
obj=obj,
|
63
|
+
parent=self,
|
64
|
+
item=item,
|
65
|
+
**kwargs,
|
66
|
+
)
|
67
|
+
|
68
|
+
def rewrite_none(self, ctx: Context[None]) -> ta.Any:
|
69
|
+
return ctx.obj
|
70
|
+
|
71
|
+
def rewrite_dataclass(self, ctx: Context[T]) -> T:
|
72
|
+
kw = {}
|
73
|
+
for f in dc.fields(ctx.obj): # type: ignore
|
74
|
+
fv = getattr(ctx.obj, f.name)
|
75
|
+
nfv: ta.Any = self.rewrite(ctx.make_child(
|
76
|
+
fv,
|
77
|
+
f.name,
|
78
|
+
raw=bool(not f.metadata.get(RawConfigMetadata)),
|
79
|
+
))
|
80
|
+
if fv is not nfv:
|
81
|
+
kw[f.name] = nfv
|
82
|
+
if not kw:
|
83
|
+
return ctx.obj
|
84
|
+
return dc.replace(ctx.obj, **kw) # type: ignore
|
85
|
+
|
86
|
+
def rewrite_str(self, ctx: Context[StrT]) -> StrT:
|
87
|
+
return ctx.obj
|
88
|
+
|
89
|
+
def rewrite_builtin_scalar_iterable(self, ctx: Context[IterableT]) -> IterableT:
|
90
|
+
return ctx.obj
|
91
|
+
|
92
|
+
def rewrite_mapping(self, ctx: Context[MappingT]) -> MappingT:
|
93
|
+
nm = []
|
94
|
+
b = False
|
95
|
+
for mk, mv in ctx.obj.items():
|
96
|
+
nk: ta.Any = self.rewrite(ctx.make_child(mk, None))
|
97
|
+
nv: ta.Any = self.rewrite(ctx.make_child(mv, nk))
|
98
|
+
nm.append((nk, nv))
|
99
|
+
b |= nk is not mk or nv is not mv
|
100
|
+
if not b:
|
101
|
+
return ctx.obj
|
102
|
+
return type(ctx.obj)(nm) # type: ignore
|
103
|
+
|
104
|
+
def rewrite_iterable(self, ctx: Context[IterableT]) -> IterableT:
|
105
|
+
nl = []
|
106
|
+
b = False
|
107
|
+
for i, le in enumerate(ctx.obj):
|
108
|
+
ne: ta.Any = self.rewrite(ctx.make_child(le, i))
|
109
|
+
nl.append(ne)
|
110
|
+
b |= ne is not le
|
111
|
+
if not b:
|
112
|
+
return ctx.obj
|
113
|
+
return type(ctx.obj)(nl) # type: ignore
|
114
|
+
|
115
|
+
def rewrite_other(self, ctx: Context[T]) -> T:
|
116
|
+
return ctx.obj
|
117
|
+
|
118
|
+
def rewrite(self, ctx: Context[T]) -> T:
|
119
|
+
if ctx.obj is None:
|
120
|
+
return self.rewrite_none(ctx) # type: ignore
|
121
|
+
|
122
|
+
elif dc.is_dataclass(ctx.obj):
|
123
|
+
return self.rewrite_dataclass(ctx)
|
124
|
+
|
125
|
+
elif isinstance(ctx.obj, str):
|
126
|
+
return self.rewrite_str(ctx) # type: ignore
|
127
|
+
|
128
|
+
elif isinstance(ctx.obj, BUILTIN_SCALAR_ITERABLE_TYPES):
|
129
|
+
return self.rewrite_builtin_scalar_iterable(ctx) # type: ignore
|
130
|
+
|
131
|
+
elif isinstance(ctx.obj, collections.abc.Mapping):
|
132
|
+
return self.rewrite_mapping(ctx) # type: ignore
|
133
|
+
|
134
|
+
elif isinstance(ctx.obj, (collections.abc.Sequence, collections.abc.Set)):
|
135
|
+
return self.rewrite_iterable(ctx) # type: ignore
|
136
|
+
|
137
|
+
else:
|
138
|
+
return self.rewrite_other(ctx)
|
139
|
+
|
140
|
+
def __call__(self, v: T) -> T:
|
141
|
+
return self.rewrite(self.Context(obj=v))
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# ruff: noqa: UP006 UP007
|
2
|
+
# @omlish-lite
|
3
|
+
"""
|
4
|
+
TODO:
|
5
|
+
- env vars
|
6
|
+
- coalescing - {$FOO|$BAR|baz}
|
7
|
+
- minja?
|
8
|
+
"""
|
9
|
+
import typing as ta
|
10
|
+
|
11
|
+
from .rewriting import ConfigRewriter
|
12
|
+
|
13
|
+
|
14
|
+
T = ta.TypeVar('T')
|
15
|
+
StrT = ta.TypeVar('StrT', bound=str)
|
16
|
+
|
17
|
+
|
18
|
+
##
|
19
|
+
|
20
|
+
|
21
|
+
class StringConfigRewriter(ConfigRewriter):
|
22
|
+
def __init__(
|
23
|
+
self,
|
24
|
+
fn: ta.Optional[ta.Callable[[str], str]] = None,
|
25
|
+
) -> None:
|
26
|
+
super().__init__()
|
27
|
+
|
28
|
+
self._fn = fn
|
29
|
+
|
30
|
+
def rewrite_str(self, ctx: ConfigRewriter.Context[StrT]) -> StrT:
|
31
|
+
v = ctx.obj
|
32
|
+
if (fn := self._fn) is not None:
|
33
|
+
if not ctx.raw:
|
34
|
+
v = fn(v) # type: ignore
|
35
|
+
return type(v)(v)
|
36
|
+
|
37
|
+
|
38
|
+
##
|
39
|
+
|
40
|
+
|
41
|
+
def format_config_strings(v: T, rpl: ta.Mapping[str, str]) -> T:
|
42
|
+
def fn(v):
|
43
|
+
return v.format(**rpl)
|
44
|
+
|
45
|
+
return StringConfigRewriter(fn)(v)
|
omlish/configs/types.py
ADDED
omlish/formats/__init__.py
CHANGED
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
|