omlish 0.0.0.dev192__py3-none-any.whl → 0.0.0.dev194__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.
Files changed (34) hide show
  1. omlish/.manifests.json +17 -3
  2. omlish/__about__.py +2 -2
  3. omlish/codecs/base.py +2 -0
  4. omlish/configs/__init__.py +0 -5
  5. omlish/configs/formats.py +247 -0
  6. omlish/configs/nginx.py +72 -0
  7. omlish/configs/processing/__init__.py +0 -0
  8. omlish/configs/{flattening.py → processing/flattening.py} +31 -33
  9. omlish/configs/processing/inheritance.py +58 -0
  10. omlish/configs/processing/matching.py +53 -0
  11. omlish/configs/processing/names.py +50 -0
  12. omlish/configs/processing/rewriting.py +141 -0
  13. omlish/configs/processing/strings.py +45 -0
  14. omlish/configs/types.py +9 -0
  15. omlish/formats/__init__.py +4 -0
  16. omlish/formats/ini/__init__.py +0 -0
  17. omlish/formats/ini/codec.py +26 -0
  18. omlish/formats/ini/sections.py +45 -0
  19. omlish/formats/toml/__init__.py +0 -0
  20. omlish/formats/{toml.py → toml/codec.py} +2 -2
  21. omlish/formats/toml/parser.py +827 -0
  22. omlish/formats/toml/writer.py +124 -0
  23. omlish/lang/__init__.py +4 -1
  24. omlish/lang/iterables.py +0 -7
  25. omlish/lite/configs.py +38 -0
  26. omlish/lite/types.py +9 -0
  27. omlish/text/glyphsplit.py +25 -10
  28. {omlish-0.0.0.dev192.dist-info → omlish-0.0.0.dev194.dist-info}/METADATA +1 -1
  29. {omlish-0.0.0.dev192.dist-info → omlish-0.0.0.dev194.dist-info}/RECORD +33 -17
  30. omlish/configs/strings.py +0 -96
  31. {omlish-0.0.0.dev192.dist-info → omlish-0.0.0.dev194.dist-info}/LICENSE +0 -0
  32. {omlish-0.0.0.dev192.dist-info → omlish-0.0.0.dev194.dist-info}/WHEEL +0 -0
  33. {omlish-0.0.0.dev192.dist-info → omlish-0.0.0.dev194.dist-info}/entry_points.txt +0 -0
  34. {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)
@@ -0,0 +1,9 @@
1
+ # ruff: noqa: UP006 UP007
2
+ # @omlish-lite
3
+ import typing as ta
4
+
5
+
6
+ ConfigMap = ta.Mapping[str, ta.Any]
7
+
8
+
9
+ #
@@ -0,0 +1,4 @@
1
+ """
2
+ TODO:
3
+ - csv
4
+ """
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
@@ -1,7 +1,7 @@
1
1
  import tomllib
2
2
 
3
- from .codecs import make_object_lazy_loaded_codec
4
- from .codecs import make_str_object_codec
3
+ from ..codecs import make_object_lazy_loaded_codec
4
+ from ..codecs import make_str_object_codec
5
5
 
6
6
 
7
7
  ##