omlish 0.0.0.dev264__py3-none-any.whl → 0.0.0.dev266__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/__about__.py +5 -5
- omlish/collections/__init__.py +5 -0
- omlish/collections/abc.py +24 -0
- omlish/collections/cache/descriptor.py +3 -0
- omlish/collections/cache/impl.py +3 -0
- omlish/collections/cache/types.py +3 -0
- omlish/collections/coerce.py +2 -1
- omlish/collections/frozen.py +3 -0
- omlish/collections/hasheq.py +3 -0
- omlish/collections/identity.py +3 -0
- omlish/collections/kv/__init__.py +51 -0
- omlish/collections/kv/base.py +55 -0
- omlish/collections/kv/capabilities.py +46 -0
- omlish/collections/kv/filtered.py +101 -0
- omlish/collections/kv/mappings.py +76 -0
- omlish/collections/kv/transformed.py +123 -0
- omlish/collections/kv/wrappers.py +99 -0
- omlish/collections/mappings.py +3 -0
- omlish/collections/ordered.py +3 -0
- omlish/collections/persistent/persistent.py +3 -0
- omlish/collections/persistent/treap.py +5 -1
- omlish/collections/persistent/treapmap.py +3 -0
- omlish/collections/sorted/sorted.py +3 -0
- omlish/collections/unmodifiable.py +3 -0
- omlish/inject/bindings.py +3 -0
- omlish/inject/eagers.py +3 -0
- omlish/inject/elements.py +4 -1
- omlish/inject/impl/elements.py +3 -0
- omlish/inject/impl/injector.py +3 -0
- omlish/inject/impl/multis.py +3 -0
- omlish/inject/impl/proxy.py +3 -0
- omlish/inject/impl/scopes.py +3 -0
- omlish/inject/injector.py +3 -0
- omlish/inject/inspect.py +3 -0
- omlish/inject/keys.py +3 -0
- omlish/inject/listeners.py +3 -0
- omlish/inject/multis.py +2 -0
- omlish/inject/origins.py +3 -0
- omlish/inject/overrides.py +3 -0
- omlish/inject/privates.py +3 -0
- omlish/inject/providers.py +3 -0
- omlish/inject/types.py +3 -0
- omlish/inject/utils.py +3 -0
- omlish/lang/__init__.py +2 -0
- omlish/lang/functions.py +14 -1
- omlish/lang/objects.py +18 -0
- omlish/term/codes.py +25 -17
- omlish/term/progressbar.py +29 -8
- {omlish-0.0.0.dev264.dist-info → omlish-0.0.0.dev266.dist-info}/METADATA +7 -7
- {omlish-0.0.0.dev264.dist-info → omlish-0.0.0.dev266.dist-info}/RECORD +54 -47
- {omlish-0.0.0.dev264.dist-info → omlish-0.0.0.dev266.dist-info}/WHEEL +0 -0
- {omlish-0.0.0.dev264.dist-info → omlish-0.0.0.dev266.dist-info}/entry_points.txt +0 -0
- {omlish-0.0.0.dev264.dist-info → omlish-0.0.0.dev266.dist-info}/licenses/LICENSE +0 -0
- {omlish-0.0.0.dev264.dist-info → omlish-0.0.0.dev266.dist-info}/top_level.txt +0 -0
omlish/__about__.py
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
__version__ = '0.0.0.
|
2
|
-
__revision__ = '
|
1
|
+
__version__ = '0.0.0.dev266'
|
2
|
+
__revision__ = '965387f5aa0862e8b1e30cbd03e24adb0a3e87bc'
|
3
3
|
|
4
4
|
|
5
5
|
#
|
@@ -99,15 +99,15 @@ class Project(ProjectBase):
|
|
99
99
|
'aiosqlite ~= 0.21',
|
100
100
|
'asyncpg ~= 0.30',
|
101
101
|
|
102
|
-
'apsw ~= 3.
|
102
|
+
'apsw ~= 3.49',
|
103
103
|
|
104
|
-
'sqlean.py ~= 3.
|
104
|
+
'sqlean.py ~= 3.47',
|
105
105
|
|
106
106
|
'duckdb ~= 1.2',
|
107
107
|
],
|
108
108
|
|
109
109
|
'testing': [
|
110
|
-
'pytest ~= 8.
|
110
|
+
'pytest ~= 8.3',
|
111
111
|
],
|
112
112
|
}
|
113
113
|
|
omlish/collections/__init__.py
CHANGED
omlish/collections/abc.py
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
# ruff: noqa: ANN204
|
2
2
|
|
3
|
+
|
3
4
|
class Hashable:
|
4
5
|
def __hash__(self): ...
|
5
6
|
|
@@ -156,3 +157,26 @@ class MutableMapping(Mapping):
|
|
156
157
|
|
157
158
|
|
158
159
|
# endregion
|
160
|
+
|
161
|
+
|
162
|
+
# region Views
|
163
|
+
|
164
|
+
|
165
|
+
class MappingView(Sized):
|
166
|
+
@property
|
167
|
+
def _mapping(self): ... # noqa
|
168
|
+
|
169
|
+
|
170
|
+
class KeysView(MappingView, Set):
|
171
|
+
pass
|
172
|
+
|
173
|
+
|
174
|
+
class ValuesView(MappingView, Collection):
|
175
|
+
pass
|
176
|
+
|
177
|
+
|
178
|
+
class ItemsView(MappingView, Set):
|
179
|
+
pass
|
180
|
+
|
181
|
+
|
182
|
+
# endregion
|
omlish/collections/cache/impl.py
CHANGED
omlish/collections/coerce.py
CHANGED
omlish/collections/frozen.py
CHANGED
omlish/collections/hasheq.py
CHANGED
omlish/collections/identity.py
CHANGED
@@ -0,0 +1,51 @@
|
|
1
|
+
from .base import ( # noqa
|
2
|
+
Kv,
|
3
|
+
MutableKv,
|
4
|
+
)
|
5
|
+
|
6
|
+
from .capabilities import ( # noqa
|
7
|
+
Closeable,
|
8
|
+
close,
|
9
|
+
closing,
|
10
|
+
|
11
|
+
Flushable,
|
12
|
+
flush,
|
13
|
+
)
|
14
|
+
|
15
|
+
from .filtered import ( # noqa
|
16
|
+
KeyFilteredKv,
|
17
|
+
KeyFilteredMutableKv,
|
18
|
+
|
19
|
+
ValueFilteredKeyError,
|
20
|
+
ValueFilteredKv,
|
21
|
+
ValueFilteredMutableKv,
|
22
|
+
)
|
23
|
+
|
24
|
+
from .mappings import ( # noqa
|
25
|
+
MappingKv,
|
26
|
+
MappingMutableKv,
|
27
|
+
|
28
|
+
KvMapping,
|
29
|
+
KvMutableMapping,
|
30
|
+
)
|
31
|
+
|
32
|
+
from .transformed import ( # noqa
|
33
|
+
KeyTransformedKv,
|
34
|
+
KeyTransformedMutableKey,
|
35
|
+
|
36
|
+
ValueTransformedKv,
|
37
|
+
ValueTransformedMutableKv,
|
38
|
+
)
|
39
|
+
|
40
|
+
from .wrappers import ( # noqa
|
41
|
+
WrapperKv,
|
42
|
+
|
43
|
+
underlying,
|
44
|
+
underlying_of,
|
45
|
+
|
46
|
+
SimpleWrapperKv,
|
47
|
+
SimpleWrapperMutableKv,
|
48
|
+
|
49
|
+
UnmodifiableError,
|
50
|
+
UnmodifiableKv,
|
51
|
+
)
|
@@ -0,0 +1,55 @@
|
|
1
|
+
"""
|
2
|
+
TODO:
|
3
|
+
- further decomp?
|
4
|
+
- Sized + Iterable?
|
5
|
+
- COM-style QueryInterface? :|
|
6
|
+
- OpKv
|
7
|
+
- table ala guava - (row key, column key) keys, sparse storage
|
8
|
+
- router
|
9
|
+
- value thunker idiom - for key-iterable-only storage, transform Kv[K, V], to Kv[K, ta.Callable[[], V]]
|
10
|
+
- zict classes
|
11
|
+
- AsyncBuffer
|
12
|
+
- Buffer
|
13
|
+
- Cache
|
14
|
+
- File
|
15
|
+
- Func
|
16
|
+
- LMDB
|
17
|
+
- LRU
|
18
|
+
- Sieve
|
19
|
+
- Zip
|
20
|
+
"""
|
21
|
+
import abc
|
22
|
+
import typing as ta
|
23
|
+
|
24
|
+
from ... import lang
|
25
|
+
|
26
|
+
|
27
|
+
K = ta.TypeVar('K')
|
28
|
+
V = ta.TypeVar('V')
|
29
|
+
|
30
|
+
|
31
|
+
##
|
32
|
+
|
33
|
+
|
34
|
+
class Kv(lang.Abstract, ta.Generic[K, V]):
|
35
|
+
@abc.abstractmethod
|
36
|
+
def __getitem__(self, k: K, /) -> V:
|
37
|
+
raise NotImplementedError
|
38
|
+
|
39
|
+
@abc.abstractmethod
|
40
|
+
def __len__(self) -> int:
|
41
|
+
raise NotImplementedError
|
42
|
+
|
43
|
+
@abc.abstractmethod
|
44
|
+
def items(self) -> ta.Iterator[tuple[K, V]]:
|
45
|
+
raise NotImplementedError
|
46
|
+
|
47
|
+
|
48
|
+
class MutableKv(Kv[K, V], lang.Abstract): # noqa
|
49
|
+
@abc.abstractmethod
|
50
|
+
def __setitem__(self, k: K, v: V, /) -> None:
|
51
|
+
raise NotImplementedError
|
52
|
+
|
53
|
+
@abc.abstractmethod
|
54
|
+
def __delitem__(self, k: K, /) -> None:
|
55
|
+
raise NotImplementedError
|
@@ -0,0 +1,46 @@
|
|
1
|
+
import abc
|
2
|
+
import contextlib
|
3
|
+
import typing as ta
|
4
|
+
|
5
|
+
from ... import lang
|
6
|
+
from .base import Kv
|
7
|
+
from .wrappers import underlying_of
|
8
|
+
|
9
|
+
|
10
|
+
KvT = ta.TypeVar('KvT', bound=Kv)
|
11
|
+
|
12
|
+
|
13
|
+
##
|
14
|
+
|
15
|
+
|
16
|
+
class Closeable(lang.Abstract):
|
17
|
+
@abc.abstractmethod
|
18
|
+
def close(self) -> None:
|
19
|
+
pass
|
20
|
+
|
21
|
+
|
22
|
+
def close(root: Kv) -> None:
|
23
|
+
for c in underlying_of(root, Closeable): # type: ignore[type-abstract]
|
24
|
+
c.close()
|
25
|
+
|
26
|
+
|
27
|
+
@contextlib.contextmanager
|
28
|
+
def closing(kv: KvT) -> ta.Iterator[KvT]:
|
29
|
+
try:
|
30
|
+
yield kv
|
31
|
+
finally:
|
32
|
+
close(kv)
|
33
|
+
|
34
|
+
|
35
|
+
##
|
36
|
+
|
37
|
+
|
38
|
+
class Flushable(lang.Abstract):
|
39
|
+
@abc.abstractmethod
|
40
|
+
def flush(self) -> None:
|
41
|
+
pass
|
42
|
+
|
43
|
+
|
44
|
+
def flush(root: Kv) -> None:
|
45
|
+
for c in underlying_of(root, Flushable): # type: ignore[type-abstract]
|
46
|
+
c.flush()
|
@@ -0,0 +1,101 @@
|
|
1
|
+
import typing as ta
|
2
|
+
|
3
|
+
from ... import lang
|
4
|
+
from .base import Kv
|
5
|
+
from .base import MutableKv
|
6
|
+
from .wrappers import SimpleWrapperKv
|
7
|
+
from .wrappers import SimpleWrapperMutableKv
|
8
|
+
|
9
|
+
|
10
|
+
K = ta.TypeVar('K')
|
11
|
+
V = ta.TypeVar('V')
|
12
|
+
|
13
|
+
|
14
|
+
##
|
15
|
+
|
16
|
+
|
17
|
+
class KeyFilteredKv(SimpleWrapperKv[K, V]):
|
18
|
+
def __init__(
|
19
|
+
self,
|
20
|
+
u: Kv[K, V],
|
21
|
+
fn: ta.Callable[[K], bool],
|
22
|
+
) -> None:
|
23
|
+
super().__init__(u)
|
24
|
+
|
25
|
+
self._fn = fn
|
26
|
+
|
27
|
+
def __getitem__(self, k: K, /) -> V:
|
28
|
+
if not self._fn(k):
|
29
|
+
raise KeyError(k)
|
30
|
+
return self._u[k]
|
31
|
+
|
32
|
+
def __len__(self) -> int:
|
33
|
+
return lang.ilen(self.items())
|
34
|
+
|
35
|
+
def items(self) -> ta.Iterator[tuple[K, V]]:
|
36
|
+
fn = self._fn
|
37
|
+
return filter(lambda t: fn(t[0]), self._u.items())
|
38
|
+
|
39
|
+
|
40
|
+
class KeyFilteredMutableKv(KeyFilteredKv[K, V], SimpleWrapperMutableKv[K, V]):
|
41
|
+
def __init__(
|
42
|
+
self,
|
43
|
+
u: MutableKv[K, V],
|
44
|
+
fn: ta.Callable[[K], bool],
|
45
|
+
) -> None:
|
46
|
+
super().__init__(u, fn)
|
47
|
+
|
48
|
+
def __setitem__(self, k: K, v: V, /) -> None:
|
49
|
+
if not self._fn(k):
|
50
|
+
raise KeyError(k)
|
51
|
+
self._u[k] = v
|
52
|
+
|
53
|
+
def __delitem__(self, k: K, /) -> None:
|
54
|
+
if not self._fn(k):
|
55
|
+
raise KeyError(k)
|
56
|
+
del self._u[k]
|
57
|
+
|
58
|
+
|
59
|
+
##
|
60
|
+
|
61
|
+
|
62
|
+
class ValueFilteredKeyError(KeyError):
|
63
|
+
pass
|
64
|
+
|
65
|
+
|
66
|
+
class ValueFilteredKv(SimpleWrapperKv[K, V]):
|
67
|
+
def __init__(
|
68
|
+
self,
|
69
|
+
u: Kv[K, V],
|
70
|
+
fn: ta.Callable[[V], bool],
|
71
|
+
) -> None:
|
72
|
+
super().__init__(u)
|
73
|
+
|
74
|
+
self._fn = fn
|
75
|
+
|
76
|
+
def __getitem__(self, k: K, /) -> V:
|
77
|
+
v = self._u[k]
|
78
|
+
if not self._fn(v):
|
79
|
+
raise ValueFilteredKeyError(k)
|
80
|
+
return v
|
81
|
+
|
82
|
+
def __len__(self) -> int:
|
83
|
+
return lang.ilen(self.items())
|
84
|
+
|
85
|
+
def items(self) -> ta.Iterator[tuple[K, V]]:
|
86
|
+
fn = self._fn
|
87
|
+
return ((k, v) for k, v in self._u.items() if fn(v))
|
88
|
+
|
89
|
+
|
90
|
+
class ValueFilteredMutableKv(ValueFilteredKv[K, V], SimpleWrapperMutableKv[K, V]):
|
91
|
+
def __init__(
|
92
|
+
self,
|
93
|
+
u: MutableKv[K, V],
|
94
|
+
fn: ta.Callable[[V], bool],
|
95
|
+
) -> None:
|
96
|
+
super().__init__(u, fn)
|
97
|
+
|
98
|
+
def __setitem__(self, k: K, v: V, /) -> None:
|
99
|
+
if not self._fn(v):
|
100
|
+
raise ValueFilteredKeyError(k)
|
101
|
+
self._u[k] = v
|
@@ -0,0 +1,76 @@
|
|
1
|
+
import typing as ta
|
2
|
+
|
3
|
+
from .base import Kv
|
4
|
+
from .base import MutableKv
|
5
|
+
|
6
|
+
|
7
|
+
K = ta.TypeVar('K')
|
8
|
+
V = ta.TypeVar('V')
|
9
|
+
|
10
|
+
|
11
|
+
##
|
12
|
+
|
13
|
+
|
14
|
+
class MappingKv(Kv[K, V]):
|
15
|
+
def __init__(self, m: ta.Mapping[K, V]) -> None:
|
16
|
+
super().__init__()
|
17
|
+
|
18
|
+
self._m = m
|
19
|
+
|
20
|
+
def __getitem__(self, k: K, /) -> V:
|
21
|
+
return self._m[k]
|
22
|
+
|
23
|
+
def __len__(self) -> int:
|
24
|
+
return len(self._m)
|
25
|
+
|
26
|
+
def items(self) -> ta.Iterator[tuple[K, V]]:
|
27
|
+
return iter(self._m.items())
|
28
|
+
|
29
|
+
|
30
|
+
class MappingMutableKv(MappingKv[K, V], MutableKv[K, V]):
|
31
|
+
def __init__(self, m: ta.MutableMapping[K, V]) -> None:
|
32
|
+
super().__init__(m)
|
33
|
+
|
34
|
+
_m: ta.MutableMapping[K, V]
|
35
|
+
|
36
|
+
def __setitem__(self, k: K, v: V, /) -> None:
|
37
|
+
self._m[k] = v
|
38
|
+
|
39
|
+
def __delitem__(self, k: K, /) -> None:
|
40
|
+
del self._m[k]
|
41
|
+
|
42
|
+
|
43
|
+
##
|
44
|
+
|
45
|
+
|
46
|
+
class KvMapping(ta.Mapping[K, V]):
|
47
|
+
def __init__(self, kv: Kv[K, V]) -> None:
|
48
|
+
super().__init__()
|
49
|
+
|
50
|
+
self._kv = kv
|
51
|
+
|
52
|
+
def __getitem__(self, key: K, /) -> V:
|
53
|
+
return self._kv[key]
|
54
|
+
|
55
|
+
def __len__(self) -> int:
|
56
|
+
return len(self._kv)
|
57
|
+
|
58
|
+
# FIXME: ItemsView
|
59
|
+
def items(self) -> ta.Iterator[tuple[K, V]]: # type: ignore[override]
|
60
|
+
return iter(self._kv.items())
|
61
|
+
|
62
|
+
def __iter__(self) -> ta.Iterator[K]:
|
63
|
+
return (k for k, v in self.items())
|
64
|
+
|
65
|
+
|
66
|
+
class KvMutableMapping(KvMapping[K, V], ta.MutableMapping[K, V]):
|
67
|
+
def __init__(self, kv: MutableKv[K, V]) -> None:
|
68
|
+
super().__init__(kv)
|
69
|
+
|
70
|
+
_kv: MutableKv[K, V]
|
71
|
+
|
72
|
+
def __setitem__(self, key: K, value: V, /) -> None:
|
73
|
+
self._kv[key] = value
|
74
|
+
|
75
|
+
def __delitem__(self, key: K, /) -> None:
|
76
|
+
del self._kv[key]
|
@@ -0,0 +1,123 @@
|
|
1
|
+
import typing as ta
|
2
|
+
|
3
|
+
from ... import check
|
4
|
+
from .base import Kv
|
5
|
+
from .base import MutableKv
|
6
|
+
from .wrappers import WrapperKv
|
7
|
+
|
8
|
+
|
9
|
+
K = ta.TypeVar('K')
|
10
|
+
V = ta.TypeVar('V')
|
11
|
+
|
12
|
+
KF = ta.TypeVar('KF')
|
13
|
+
KT = ta.TypeVar('KT')
|
14
|
+
VF = ta.TypeVar('VF')
|
15
|
+
VT = ta.TypeVar('VT')
|
16
|
+
|
17
|
+
|
18
|
+
##
|
19
|
+
|
20
|
+
|
21
|
+
class KeyTransformedKv(WrapperKv[KT, V], ta.Generic[KT, KF, V]):
|
22
|
+
def __init__(
|
23
|
+
self,
|
24
|
+
u: Kv[KF, V],
|
25
|
+
*,
|
26
|
+
t_to_f: ta.Callable[[KT], KF] | None = None,
|
27
|
+
f_to_t: ta.Callable[[KF], KT] | None = None,
|
28
|
+
) -> None:
|
29
|
+
super().__init__()
|
30
|
+
|
31
|
+
self._u = u
|
32
|
+
self._t_to_f = t_to_f
|
33
|
+
self._f_to_t = f_to_t
|
34
|
+
|
35
|
+
def underlying(self) -> ta.Sequence[Kv]:
|
36
|
+
return [self._u]
|
37
|
+
|
38
|
+
def __getitem__(self, k: KT, /) -> V:
|
39
|
+
fn = check.not_none(self._t_to_f)
|
40
|
+
return self._u[fn(k)]
|
41
|
+
|
42
|
+
def __len__(self) -> int:
|
43
|
+
return len(self._u)
|
44
|
+
|
45
|
+
def items(self) -> ta.Iterator[tuple[KT, V]]:
|
46
|
+
fn = check.not_none(self._f_to_t)
|
47
|
+
return ((fn(k), v) for k, v in self._u.items())
|
48
|
+
|
49
|
+
|
50
|
+
class KeyTransformedMutableKey(KeyTransformedKv[KT, KF, V], MutableKv[KT, V], ta.Generic[KT, KF, V]):
|
51
|
+
def __init__(
|
52
|
+
self,
|
53
|
+
u: MutableKv[KF, V],
|
54
|
+
*,
|
55
|
+
t_to_f: ta.Callable[[KT], KF] | None = None,
|
56
|
+
f_to_t: ta.Callable[[KF], KT] | None = None,
|
57
|
+
) -> None:
|
58
|
+
super().__init__(
|
59
|
+
u,
|
60
|
+
t_to_f=t_to_f,
|
61
|
+
f_to_t=f_to_t,
|
62
|
+
)
|
63
|
+
|
64
|
+
_u: MutableKv[KF, V]
|
65
|
+
|
66
|
+
def __setitem__(self, k: KT, v: V, /) -> None:
|
67
|
+
fn = check.not_none(self._t_to_f)
|
68
|
+
self._u[fn(k)] = v
|
69
|
+
|
70
|
+
def __delitem__(self, k: KT, /) -> None:
|
71
|
+
fn = check.not_none(self._t_to_f)
|
72
|
+
del self._u[fn(k)]
|
73
|
+
|
74
|
+
|
75
|
+
##
|
76
|
+
|
77
|
+
|
78
|
+
class ValueTransformedKv(WrapperKv[K, VT], ta.Generic[K, VT, VF]):
|
79
|
+
def __init__(
|
80
|
+
self,
|
81
|
+
u: Kv[K, VF],
|
82
|
+
f_to_t: ta.Callable[[VF], VT] | None = None,
|
83
|
+
) -> None:
|
84
|
+
super().__init__()
|
85
|
+
|
86
|
+
self._u = u
|
87
|
+
self._f_to_t = f_to_t
|
88
|
+
|
89
|
+
def underlying(self) -> ta.Sequence[Kv]:
|
90
|
+
return [self._u]
|
91
|
+
|
92
|
+
def __getitem__(self, k: K, /) -> VT:
|
93
|
+
fn = check.not_none(self._f_to_t)
|
94
|
+
return fn(self._u[k])
|
95
|
+
|
96
|
+
def __len__(self) -> int:
|
97
|
+
return len(self._u)
|
98
|
+
|
99
|
+
def items(self) -> ta.Iterator[tuple[K, VT]]:
|
100
|
+
fn = check.not_none(self._f_to_t)
|
101
|
+
return ((k, fn(v)) for k, v in self._u.items())
|
102
|
+
|
103
|
+
|
104
|
+
class ValueTransformedMutableKv(ValueTransformedKv[K, VT, VF], MutableKv[K, VT], ta.Generic[K, VT, VF]):
|
105
|
+
def __init__(
|
106
|
+
self,
|
107
|
+
u: MutableKv[K, VF],
|
108
|
+
*,
|
109
|
+
f_to_t: ta.Callable[[VF], VT] | None = None,
|
110
|
+
t_to_f: ta.Callable[[VT], VF] | None = None,
|
111
|
+
) -> None:
|
112
|
+
super().__init__(u, f_to_t)
|
113
|
+
|
114
|
+
self._t_to_f = t_to_f
|
115
|
+
|
116
|
+
_u: MutableKv[K, VF]
|
117
|
+
|
118
|
+
def __setitem__(self, k: K, v: VT, /) -> None:
|
119
|
+
fn = check.not_none(self._t_to_f)
|
120
|
+
self._u[k] = fn(v)
|
121
|
+
|
122
|
+
def __delitem__(self, k: K, /) -> None:
|
123
|
+
del self._u[k]
|
@@ -0,0 +1,99 @@
|
|
1
|
+
import abc
|
2
|
+
import typing as ta
|
3
|
+
|
4
|
+
from ... import lang
|
5
|
+
from .base import Kv
|
6
|
+
from .base import MutableKv
|
7
|
+
|
8
|
+
|
9
|
+
K = ta.TypeVar('K')
|
10
|
+
V = ta.TypeVar('V')
|
11
|
+
|
12
|
+
T = ta.TypeVar('T')
|
13
|
+
|
14
|
+
|
15
|
+
##
|
16
|
+
|
17
|
+
|
18
|
+
class WrapperKv(Kv[K, V], lang.Abstract):
|
19
|
+
@abc.abstractmethod
|
20
|
+
def underlying(self) -> ta.Iterable[Kv]:
|
21
|
+
raise NotImplementedError
|
22
|
+
|
23
|
+
|
24
|
+
##
|
25
|
+
|
26
|
+
|
27
|
+
def underlying(
|
28
|
+
root: Kv,
|
29
|
+
*,
|
30
|
+
leaves_only: bool = False,
|
31
|
+
filter: ta.Callable[[Kv], bool] | None = None, # noqa
|
32
|
+
) -> ta.Iterator[Kv]:
|
33
|
+
def rec(c):
|
34
|
+
if isinstance(c, WrapperKv):
|
35
|
+
if not leaves_only:
|
36
|
+
yield c
|
37
|
+
for n in c.underlying():
|
38
|
+
yield from rec(n)
|
39
|
+
else:
|
40
|
+
yield c
|
41
|
+
|
42
|
+
for u in rec(root):
|
43
|
+
if filter is not None and not filter(u):
|
44
|
+
continue
|
45
|
+
yield u
|
46
|
+
|
47
|
+
|
48
|
+
def underlying_of(root: Kv, cls: type[T]) -> ta.Iterator[T]:
|
49
|
+
return underlying(root, filter=lambda c: isinstance(c, cls)) # type: ignore[return-value]
|
50
|
+
|
51
|
+
|
52
|
+
##
|
53
|
+
|
54
|
+
|
55
|
+
class SimpleWrapperKv(WrapperKv[K, V]):
|
56
|
+
def __init__(self, u: Kv[K, V]) -> None:
|
57
|
+
super().__init__()
|
58
|
+
|
59
|
+
self._u = u
|
60
|
+
|
61
|
+
def underlying(self) -> ta.Sequence[Kv]:
|
62
|
+
return [self._u]
|
63
|
+
|
64
|
+
def __getitem__(self, k: K, /) -> V:
|
65
|
+
return self._u[k]
|
66
|
+
|
67
|
+
def __len__(self) -> int:
|
68
|
+
return len(self._u)
|
69
|
+
|
70
|
+
def items(self) -> ta.Iterator[tuple[K, V]]:
|
71
|
+
return self._u.items()
|
72
|
+
|
73
|
+
|
74
|
+
class SimpleWrapperMutableKv(SimpleWrapperKv[K, V], MutableKv[K, V]):
|
75
|
+
def __init__(self, u: MutableKv[K, V]) -> None:
|
76
|
+
super().__init__(u)
|
77
|
+
|
78
|
+
_u: MutableKv[K, V]
|
79
|
+
|
80
|
+
def __setitem__(self, k: K, v: V, /) -> None:
|
81
|
+
self._u[k] = v
|
82
|
+
|
83
|
+
def __delitem__(self, k: K, /) -> None:
|
84
|
+
del self._u[k]
|
85
|
+
|
86
|
+
|
87
|
+
##
|
88
|
+
|
89
|
+
|
90
|
+
class UnmodifiableError(Exception):
|
91
|
+
pass
|
92
|
+
|
93
|
+
|
94
|
+
class UnmodifiableKv(SimpleWrapperKv[K, V], MutableKv[K, V]):
|
95
|
+
def __setitem__(self, k: K, v: V, /) -> None:
|
96
|
+
raise UnmodifiableError
|
97
|
+
|
98
|
+
def __delitem__(self, k: K, /) -> None:
|
99
|
+
raise UnmodifiableError
|