omlish 0.0.0.dev265__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.
Files changed (32) hide show
  1. omlish/__about__.py +5 -5
  2. omlish/collections/__init__.py +5 -0
  3. omlish/collections/abc.py +24 -0
  4. omlish/collections/cache/descriptor.py +3 -0
  5. omlish/collections/cache/impl.py +3 -0
  6. omlish/collections/cache/types.py +3 -0
  7. omlish/collections/coerce.py +2 -1
  8. omlish/collections/frozen.py +3 -0
  9. omlish/collections/hasheq.py +3 -0
  10. omlish/collections/identity.py +3 -0
  11. omlish/collections/kv/__init__.py +51 -0
  12. omlish/collections/kv/base.py +55 -0
  13. omlish/collections/kv/capabilities.py +46 -0
  14. omlish/collections/kv/filtered.py +101 -0
  15. omlish/collections/kv/mappings.py +76 -0
  16. omlish/collections/kv/transformed.py +123 -0
  17. omlish/collections/kv/wrappers.py +99 -0
  18. omlish/collections/mappings.py +3 -0
  19. omlish/collections/ordered.py +3 -0
  20. omlish/collections/persistent/persistent.py +3 -0
  21. omlish/collections/persistent/treap.py +5 -1
  22. omlish/collections/persistent/treapmap.py +3 -0
  23. omlish/collections/sorted/sorted.py +3 -0
  24. omlish/collections/unmodifiable.py +3 -0
  25. omlish/lang/__init__.py +1 -0
  26. omlish/lang/functions.py +14 -1
  27. {omlish-0.0.0.dev265.dist-info → omlish-0.0.0.dev266.dist-info}/METADATA +7 -7
  28. {omlish-0.0.0.dev265.dist-info → omlish-0.0.0.dev266.dist-info}/RECORD +32 -25
  29. {omlish-0.0.0.dev265.dist-info → omlish-0.0.0.dev266.dist-info}/WHEEL +0 -0
  30. {omlish-0.0.0.dev265.dist-info → omlish-0.0.0.dev266.dist-info}/entry_points.txt +0 -0
  31. {omlish-0.0.0.dev265.dist-info → omlish-0.0.0.dev266.dist-info}/licenses/LICENSE +0 -0
  32. {omlish-0.0.0.dev265.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.dev265'
2
- __revision__ = 'f83c70eb0c46f33c859473df28f39340c4f9899b'
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.47',
102
+ 'apsw ~= 3.49',
103
103
 
104
- 'sqlean.py ~= 3.45',
104
+ 'sqlean.py ~= 3.47',
105
105
 
106
106
  'duckdb ~= 1.2',
107
107
  ],
108
108
 
109
109
  'testing': [
110
- 'pytest ~= 8.0',
110
+ 'pytest ~= 8.3',
111
111
  ],
112
112
  }
113
113
 
@@ -57,6 +57,11 @@ from .identity import ( # noqa
57
57
  IdentityWeakSet,
58
58
  )
59
59
 
60
+ if _ta.TYPE_CHECKING:
61
+ from . import kv
62
+ else:
63
+ kv = _lang.proxy_import('.kv', __package__)
64
+
60
65
  from .mappings import ( # noqa
61
66
  MissingDict,
62
67
  TypeMap,
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
@@ -15,6 +15,9 @@ C = ta.TypeVar('C', bound=ta.Callable)
15
15
  CC: ta.TypeAlias = ta.Callable[[C], C]
16
16
 
17
17
 
18
+ ##
19
+
20
+
18
21
  class Scope(enum.Enum):
19
22
  INSTANCE = 'INSTANCE'
20
23
  CLASS = 'CLASS'
@@ -30,6 +30,9 @@ V2 = ta.TypeVar('V2')
30
30
  log = logging.getLogger(__name__)
31
31
 
32
32
 
33
+ ##
34
+
35
+
33
36
  class SKIP(lang.Marker):
34
37
  pass
35
38
 
@@ -6,6 +6,9 @@ K = ta.TypeVar('K')
6
6
  V = ta.TypeVar('V')
7
7
 
8
8
 
9
+ ##
10
+
11
+
9
12
  class OverweightError(Exception):
10
13
  pass
11
14
 
@@ -12,7 +12,8 @@ K2 = ta.TypeVar('K2')
12
12
  V = ta.TypeVar('V')
13
13
  V2 = ta.TypeVar('V2')
14
14
 
15
- _map = map
15
+
16
+ ##
16
17
 
17
18
 
18
19
  def _unpack_fn(fn):
@@ -11,6 +11,9 @@ K = ta.TypeVar('K')
11
11
  V = ta.TypeVar('V')
12
12
 
13
13
 
14
+ ##
15
+
16
+
14
17
  class Frozen(ta.Hashable, abc.ABC):
15
18
  pass
16
19
 
@@ -16,6 +16,9 @@ K2 = ta.TypeVar('K2')
16
16
  V2 = ta.TypeVar('V2')
17
17
 
18
18
 
19
+ ##
20
+
21
+
19
22
  class HashEq(lang.Abstract, ta.Generic[K]):
20
23
  @abc.abstractmethod
21
24
  def hash(self, k: K) -> int:
@@ -11,6 +11,9 @@ K = ta.TypeVar('K')
11
11
  V = ta.TypeVar('V')
12
12
 
13
13
 
14
+ ##
15
+
16
+
14
17
  class IdentityWrapper(ta.Generic[T]):
15
18
  def __init__(self, value: T) -> None:
16
19
  super().__init__()
@@ -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
@@ -7,6 +7,9 @@ K = ta.TypeVar('K')
7
7
  V = ta.TypeVar('V')
8
8
 
9
9
 
10
+ ##
11
+
12
+
10
13
  def multikey_dict(dct: ta.Mapping[ta.Iterable[K] | K, V], *, deep: bool = False) -> dict[K, V]:
11
14
  ret = {}
12
15
  for k, v in dct.items():
@@ -4,6 +4,9 @@ import typing as ta
4
4
  T = ta.TypeVar('T')
5
5
 
6
6
 
7
+ ##
8
+
9
+
7
10
  class OrderedSet(ta.MutableSet[T]):
8
11
  def __init__(self, iterable: ta.Iterable[T] | None = None) -> None:
9
12
  super().__init__()
@@ -6,6 +6,9 @@ K = ta.TypeVar('K')
6
6
  V = ta.TypeVar('V')
7
7
 
8
8
 
9
+ ##
10
+
11
+
9
12
  class PersistentMap(ta.Generic[K, V], abc.ABC):
10
13
  @abc.abstractmethod
11
14
  def __len__(self) -> int:
@@ -21,7 +21,11 @@ import typing as ta
21
21
 
22
22
 
23
23
  T = ta.TypeVar('T')
24
- Comparer = ta.Callable[[T, T], int]
24
+
25
+ Comparer: ta.TypeAlias = ta.Callable[[T, T], int]
26
+
27
+
28
+ ##
25
29
 
26
30
 
27
31
  class TreapNode(ta.Generic[T]):
@@ -28,6 +28,9 @@ K = ta.TypeVar('K')
28
28
  V = ta.TypeVar('V')
29
29
 
30
30
 
31
+ ##
32
+
33
+
31
34
  class TreapMap(PersistentMap[K, V]):
32
35
  __slots__ = ('_n', '_c')
33
36
 
@@ -10,6 +10,9 @@ K = ta.TypeVar('K')
10
10
  V = ta.TypeVar('V')
11
11
 
12
12
 
13
+ ##
14
+
15
+
13
16
  class SortedCollection(lang.Abstract, ta.Collection[T]):
14
17
  Comparator = ta.Callable[[U, U], int]
15
18
 
@@ -8,6 +8,9 @@ K = ta.TypeVar('K')
8
8
  V = ta.TypeVar('V')
9
9
 
10
10
 
11
+ ##
12
+
13
+
11
14
  class Unmodifiable(lang.Abstract):
12
15
  pass
13
16
 
omlish/lang/__init__.py CHANGED
@@ -147,6 +147,7 @@ from .functions import ( # noqa
147
147
  raise_,
148
148
  raising,
149
149
  recurse,
150
+ strict_constant,
150
151
  try_,
151
152
  void,
152
153
  )
omlish/lang/functions.py CHANGED
@@ -92,16 +92,29 @@ def opt_fn(fn: ta.Callable[[F], T]) -> ta.Callable[[F | None], T | None]:
92
92
  return inner
93
93
 
94
94
 
95
- class constant(ta.Generic[T]): # noqa
95
+ ##
96
+
97
+
98
+ class _constant(ta.Generic[T]): # noqa
96
99
  def __init__(self, obj: T) -> None:
97
100
  super().__init__()
98
101
 
99
102
  self._obj = obj
100
103
 
104
+
105
+ class constant(_constant[T]): # noqa
106
+ def __call__(self, *args: ta.Any, **kwargs: ta.Any) -> T:
107
+ return self._obj
108
+
109
+
110
+ class strict_constant(_constant[T]): # noqa
101
111
  def __call__(self) -> T:
102
112
  return self._obj
103
113
 
104
114
 
115
+ ##
116
+
117
+
105
118
  def is_none(o: ta.Any) -> bool:
106
119
  return o is None
107
120
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: omlish
3
- Version: 0.0.0.dev265
3
+ Version: 0.0.0.dev266
4
4
  Summary: omlish
5
5
  Author: wrmsr
6
6
  License: BSD-3-Clause
@@ -39,10 +39,10 @@ Requires-Dist: pymysql~=1.1; extra == "all"
39
39
  Requires-Dist: aiomysql~=0.2; extra == "all"
40
40
  Requires-Dist: aiosqlite~=0.21; extra == "all"
41
41
  Requires-Dist: asyncpg~=0.30; extra == "all"
42
- Requires-Dist: apsw~=3.47; extra == "all"
43
- Requires-Dist: sqlean.py~=3.45; extra == "all"
42
+ Requires-Dist: apsw~=3.49; extra == "all"
43
+ Requires-Dist: sqlean.py~=3.47; extra == "all"
44
44
  Requires-Dist: duckdb~=1.2; extra == "all"
45
- Requires-Dist: pytest~=8.0; extra == "all"
45
+ Requires-Dist: pytest~=8.3; extra == "all"
46
46
  Requires-Dist: anyio~=4.9; extra == "all"
47
47
  Requires-Dist: sniffio~=1.3; extra == "all"
48
48
  Requires-Dist: asttokens~=3.0; extra == "all"
@@ -85,11 +85,11 @@ Requires-Dist: pymysql~=1.1; extra == "sqldrivers"
85
85
  Requires-Dist: aiomysql~=0.2; extra == "sqldrivers"
86
86
  Requires-Dist: aiosqlite~=0.21; extra == "sqldrivers"
87
87
  Requires-Dist: asyncpg~=0.30; extra == "sqldrivers"
88
- Requires-Dist: apsw~=3.47; extra == "sqldrivers"
89
- Requires-Dist: sqlean.py~=3.45; extra == "sqldrivers"
88
+ Requires-Dist: apsw~=3.49; extra == "sqldrivers"
89
+ Requires-Dist: sqlean.py~=3.47; extra == "sqldrivers"
90
90
  Requires-Dist: duckdb~=1.2; extra == "sqldrivers"
91
91
  Provides-Extra: testing
92
- Requires-Dist: pytest~=8.0; extra == "testing"
92
+ Requires-Dist: pytest~=8.3; extra == "testing"
93
93
  Provides-Extra: plus
94
94
  Requires-Dist: anyio~=4.9; extra == "plus"
95
95
  Requires-Dist: sniffio~=1.3; extra == "plus"
@@ -1,5 +1,5 @@
1
1
  omlish/.manifests.json,sha256=x26AIwDzScUvnX-p4xlq6Zc5QYrAo0Vmgf1qHc1KL_M,8253
2
- omlish/__about__.py,sha256=mUc6xs3AcgIXA_LmHEaA24dsIsYHNDRy7m0iT9wQ9og,3380
2
+ omlish/__about__.py,sha256=66KDLgGcqah6d5uVeBHruqwCEJq1zWZyc7Pj3aoae5w,3380
3
3
  omlish/__init__.py,sha256=SsyiITTuK0v74XpKV8dqNaCmjOlan1JZKrHQv5rWKPA,253
4
4
  omlish/c3.py,sha256=rer-TPOFDU6fYq_AWio_AmA-ckZ8JDY5shIzQ_yXfzA,8414
5
5
  omlish/cached.py,sha256=MLap_p0rdGoDIMVhXVHm1tsbcWobJF0OanoodV03Ju8,542
@@ -143,29 +143,36 @@ omlish/codecs/funcs.py,sha256=p4imNt7TobyZVXWC-WhntHVu9KfJrO4QwdtPRh-cVOk,850
143
143
  omlish/codecs/registry.py,sha256=2FnO5YP7ui1LzkguwESY0MP3WIdwgPTIJTM_4RyTOEg,3896
144
144
  omlish/codecs/standard.py,sha256=eiZ4u9ep0XrA4Z_D1zJI0vmWyuN8HLrX4Se_r_Cq_ZM,60
145
145
  omlish/codecs/text.py,sha256=JzrdwMpQPo2NBBg3K1EZszzQy5vEWmd82SIerJd4yeQ,5723
146
- omlish/collections/__init__.py,sha256=fAGCii4OttPRee9q4AD-IfQpdsmoCdgPwYUMPgnJwCs,2140
147
- omlish/collections/abc.py,sha256=sP7BpTVhx6s6C59mTFeosBi4rHOWC6tbFBYbxdZmvh0,2365
148
- omlish/collections/coerce.py,sha256=g68ROb_-5HgH-vI8612mU2S0FZ8-wp2ZHK5_Zy_kVC0,7037
146
+ omlish/collections/__init__.py,sha256=vWVm-M5WsX8S9xw9q67Jv4FKCE1GW6JMUNrUVq5pxWU,2238
147
+ omlish/collections/abc.py,sha256=ikTJlJ5dhXjU6tlNsI0Wm0_7GaIEpe3mftpvdGY_nc8,2620
148
+ omlish/collections/coerce.py,sha256=tAls15v_7p5bUN33R7Zbko87KW5toWHl9fRialCqyNY,7030
149
149
  omlish/collections/exceptions.py,sha256=shcS-NCnEUudF8qC_SmO2TQyjivKlS4TDjaz_faqQ0c,44
150
- omlish/collections/frozen.py,sha256=jQppK1pyQ3e_aAvw8OEKfnr7b0OB4RI5Qr1g9xXTZaQ,4137
151
- omlish/collections/hasheq.py,sha256=SQdVICLZWKkYu4vUXrfmWBXO3i-jx01iM9IInDWkKfU,3664
152
- omlish/collections/identity.py,sha256=1kdiByfzKHGQZgUg1vkwILt8oPPQgerGh0_HbLDdqKw,2835
153
- omlish/collections/mappings.py,sha256=fCHQatlAstiZkWZiyIlOw637Yep7ce79EPPbJcWHHUA,2784
154
- omlish/collections/ordered.py,sha256=tUAl99XHbSbzn7Hdh99jUBl27NcC2J7ZTI67slTMe5M,2333
150
+ omlish/collections/frozen.py,sha256=LMbAHYDENIQk1hvjCTvpnx66m1TalrHa4CSn8n_tsXQ,4142
151
+ omlish/collections/hasheq.py,sha256=swOBPEnU_C0SU3VqWJX9mr0BfZLD0A-4Ke9Vahj3fE4,3669
152
+ omlish/collections/identity.py,sha256=32c1w-90OjwP9FlD-66yp4h_Y7cLfTmEUgp-MQdL8T8,2840
153
+ omlish/collections/mappings.py,sha256=u0UrB550nBM_RNXQV0YnBTbRZEWrplZe9ZxcCN3H65M,2789
154
+ omlish/collections/ordered.py,sha256=7zTbrAt12rf6i33XHkQERKar258fJacaw_WbtGEBgWo,2338
155
155
  omlish/collections/ranked.py,sha256=rg6DL36oOUiG5JQEAkGnT8b6f9mSndQlIovtt8GQj_w,2229
156
- omlish/collections/unmodifiable.py,sha256=-zys__n6L7liWzhmHAIvfxprq7cUE5HoR3foGvXc_7I,4748
156
+ omlish/collections/unmodifiable.py,sha256=X7kKhPFdZF4m28SfLDxZL-riWlhbZffdPv35aTP30YM,4753
157
157
  omlish/collections/utils.py,sha256=Q0lHhNDokVxdOvApmu1QX5fABYwbn1ATiIwp194Ur_E,2889
158
158
  omlish/collections/cache/__init__.py,sha256=D1gO71VcwxFTZP9gAc9isHfg_TEdalwhsJcgGLvS9hg,233
159
- omlish/collections/cache/descriptor.py,sha256=aa-OOChFAJLMPHjuc8YPCvVsE0INntPxxXoq-kl4jtg,5021
160
- omlish/collections/cache/impl.py,sha256=ySRU9UJG7jH9VPvuXdwZQ_rSqrleY-1mtie5Ml738wY,14755
161
- omlish/collections/cache/types.py,sha256=yNjwd6CGyTJQdxN2CQxFqqBAlcs1Z7vvNV-aU1K7p8E,685
159
+ omlish/collections/cache/descriptor.py,sha256=F9aRsF-xOUcNMzTwIWrUpKTjop1Z-oItQqJDwVaR0FU,5026
160
+ omlish/collections/cache/impl.py,sha256=Y18OcAsNL6dIWuk89UlZBpqq0iBU-P4VDio6eis43Us,14760
161
+ omlish/collections/cache/types.py,sha256=uND_qOk8bVVmdhrOhjx9QHYqs2jq53NThEqQAl3Nepw,690
162
+ omlish/collections/kv/__init__.py,sha256=qPuE8bmbyOkT_qVGH5owSp0SbC9xI_p_LS0tP7S7QSw,751
163
+ omlish/collections/kv/base.py,sha256=QDAwnWQFnyfWoZB0rlSTvfO-m-YED9MBi5nojDt8n-g,1085
164
+ omlish/collections/kv/capabilities.py,sha256=ZINohQKPuUGJNbUnwm6CExMoCKrOcftrUWzFF0xlSww,752
165
+ omlish/collections/kv/filtered.py,sha256=EJS885-skKEilRy9noblTUU_4RY04jIYet9OMDQwQPo,2266
166
+ omlish/collections/kv/mappings.py,sha256=Y67h6mY4MpBfOUXZCyW_Gi7xuiAzTq7KzB4qIldqG10,1615
167
+ omlish/collections/kv/transformed.py,sha256=Wtzqz08f4w1RtR51rNtkU45ZCpYEKeQAqhzIpDWONHs,3001
168
+ omlish/collections/kv/wrappers.py,sha256=nUtoiArK1Fu2TgxFrqZU69bEoAxKJ_nA7qMeeihIz3U,1985
162
169
  omlish/collections/persistent/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
163
- omlish/collections/persistent/persistent.py,sha256=KG471s0bhhReQrjlmX0xaN9HeAIcrtT264ddZCxsExo,875
164
- omlish/collections/persistent/treap.py,sha256=A09ZPacGyJlyRB-Wi4TNj3tE0w-RpFNliPgpDaa6Vwg,7719
165
- omlish/collections/persistent/treapmap.py,sha256=TxOM-ZRF5PK2xe5wRIhESNt7DGh9b_MeZfE7HLkCOs4,5804
170
+ omlish/collections/persistent/persistent.py,sha256=6CuzeZjZMqBLflU-CuWu32SrtZXFrJOV-H_UUuYoTkg,880
171
+ omlish/collections/persistent/treap.py,sha256=o7vhnn8kHde_Plk0sojlJZkkKwp8hpj2IekhcvbYqHs,7739
172
+ omlish/collections/persistent/treapmap.py,sha256=dBCZHouClUhvUBnSR5k97AAu09EQVRWdUOwwc1CHPmg,5809
166
173
  omlish/collections/sorted/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
167
174
  omlish/collections/sorted/skiplist.py,sha256=tybcD8OslDBCc86Z1qKb4GRkbhMY26qorPzPIeqFmKk,6031
168
- omlish/collections/sorted/sorted.py,sha256=euHJan3FqTYSCJGsVcYYRV-yhAAQ5_htnjymnNoVHRE,3319
175
+ omlish/collections/sorted/sorted.py,sha256=UhjJce7ulO_FUB6dFOhKpEg9Bcgxr2m6VXeCNtbLjSM,3324
169
176
  omlish/concurrent/__init__.py,sha256=9p-s8MvBEYDqHIoYU3OYoe-Nni22QdkW7nhZGEukJTM,197
170
177
  omlish/concurrent/executors.py,sha256=mF-rjJWzNFxwB1-_H7rHuwoImpl4FtNM6W3wcqM3NEE,1291
171
178
  omlish/concurrent/futures.py,sha256=870tx8ELI8THvMnTrQoYIlEFKO9hM4KUrlehckJqKBU,4238
@@ -408,7 +415,7 @@ omlish/iterators/iterators.py,sha256=iTQQwBE6Wzoy36dnbPIws17zbjE3zNN4KwVw4Fzh-gY
408
415
  omlish/iterators/recipes.py,sha256=53mkexitMhkwXQZbL6DrhpT0WePQ_56uXd5Jaw3DfzI,467
409
416
  omlish/iterators/tools.py,sha256=Pi4ybXytUXVZ3xwK89xpPImQfYYId9p1vIFQvVqVLqA,2551
410
417
  omlish/iterators/unique.py,sha256=0jAX3kwzVfRNhe0Tmh7kVP_Q2WBIn8POo_O-rgFV0rQ,1390
411
- omlish/lang/__init__.py,sha256=aSU-1zjUxrLH-3FPpogKIxPBfOMiCzC9TOKRBajo1fA,5093
418
+ omlish/lang/__init__.py,sha256=-fPR8lvFU1f2Sk8CGMkF0HQs1mrwKhp0ufM4zla2jz8,5114
412
419
  omlish/lang/attrs.py,sha256=fofCKN0X8TMu1yGqHpLpNLih9r9HWl3D3Vn3b6O791w,3891
413
420
  omlish/lang/clsdct.py,sha256=HAGIvBSbCefzRjXriwYSBLO7QHKRv2UsE78jixOb-fA,1828
414
421
  omlish/lang/collections.py,sha256=aGi0j6VzVe2nz4l357Y4RD5_XNl8OJbmM5qM6BclrrY,1895
@@ -417,7 +424,7 @@ omlish/lang/contextmanagers.py,sha256=UPH6daYwSP9cH5AfSVsJyEHk1UURMGhVPM5ZRhp_Hv
417
424
  omlish/lang/datetimes.py,sha256=ehI_DhQRM-bDxAavnp470XcekbbXc4Gdw9y1KpHDJT0,223
418
425
  omlish/lang/descriptors.py,sha256=zBtgO9LjdSTGHNUgiIqswh78WOVoGH6KzS0NbgB1Wls,6572
419
426
  omlish/lang/exceptions.py,sha256=qJBo3NU1mOWWm-NhQUHCY5feYXR3arZVyEHinLsmRH4,47
420
- omlish/lang/functions.py,sha256=RbUt10UjDj95CvdCDtEC5F_xrEmbsPk1YPKjIg4S5Jc,4508
427
+ omlish/lang/functions.py,sha256=AzU0yseBdR-J-o4plpfCnWh-MZAZn271xQZVRo4cBFg,4692
421
428
  omlish/lang/generators.py,sha256=5LX17j-Ej3QXhwBgZvRTm_dq3n9veC4IOUcVmvSu2vU,5243
422
429
  omlish/lang/imports.py,sha256=Gdl6xCF89xiMOE1yDmdvKWamLq8HX-XPianO58Jdpmw,9218
423
430
  omlish/lang/iterables.py,sha256=HOjcxOwyI5bBApDLsxRAGGhTTmw7fdZl2kEckxRVl-0,1994
@@ -768,9 +775,9 @@ omlish/text/parts.py,sha256=Q9NvoyEGQKIWgiPD4D_Qc66cWAuyEKE033dT9m7c3Wk,6662
768
775
  omlish/text/random.py,sha256=8feS5JE_tSjYlMl-lp0j93kCfzBae9AM2cXlRLebXMA,199
769
776
  omlish/text/go/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
770
777
  omlish/text/go/quoting.py,sha256=N9EYdnFdEX_A8fOviH-1w4jwV3XOQ7VU2WsoUNubYVY,9137
771
- omlish-0.0.0.dev265.dist-info/licenses/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
772
- omlish-0.0.0.dev265.dist-info/METADATA,sha256=bfiaKjcUegKuHHiSKfGvlXXvdg9KKeuO3T_2-rfv6p8,4198
773
- omlish-0.0.0.dev265.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
774
- omlish-0.0.0.dev265.dist-info/entry_points.txt,sha256=Lt84WvRZJskWCAS7xnQGZIeVWksprtUHj0llrvVmod8,35
775
- omlish-0.0.0.dev265.dist-info/top_level.txt,sha256=pePsKdLu7DvtUiecdYXJ78iO80uDNmBlqe-8hOzOmfs,7
776
- omlish-0.0.0.dev265.dist-info/RECORD,,
778
+ omlish-0.0.0.dev266.dist-info/licenses/LICENSE,sha256=B_hVtavaA8zCYDW99DYdcpDLKz1n3BBRjZrcbv8uG8c,1451
779
+ omlish-0.0.0.dev266.dist-info/METADATA,sha256=k1zJGhmaDUCC8eluYhSrRZm5BGeRFiA5MZgsdCoG39k,4198
780
+ omlish-0.0.0.dev266.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
781
+ omlish-0.0.0.dev266.dist-info/entry_points.txt,sha256=Lt84WvRZJskWCAS7xnQGZIeVWksprtUHj0llrvVmod8,35
782
+ omlish-0.0.0.dev266.dist-info/top_level.txt,sha256=pePsKdLu7DvtUiecdYXJ78iO80uDNmBlqe-8hOzOmfs,7
783
+ omlish-0.0.0.dev266.dist-info/RECORD,,