omlish 0.0.0.dev295__py3-none-any.whl → 0.0.0.dev297__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 +4 -2
- omlish/collections/__init__.py +5 -0
- omlish/collections/persistent/persistent.py +26 -5
- omlish/collections/persistent/treapmap.py +35 -12
- omlish/collections/sorted/skiplist.py +27 -19
- omlish/collections/sorted/sorted.py +49 -12
- omlish/dataclasses/generation/processor.py +5 -2
- omlish/dataclasses/processing/base.py +7 -2
- omlish/dataclasses/processing/driving.py +2 -2
- omlish/dom/__init__.py +26 -0
- omlish/dom/building.py +54 -0
- omlish/dom/content.py +129 -0
- omlish/dom/rendering.py +184 -0
- omlish/math/__init__.py +83 -0
- omlish/math/bits.py +0 -153
- omlish/math/c.py +13 -0
- omlish/math/fixed.py +390 -0
- omlish/math/floats.py +3 -0
- omlish/math/histogram.py +127 -0
- omlish/math/stats.py +0 -124
- omlish/sql/__init__.py +16 -0
- omlish/sql/api/__init__.py +7 -0
- omlish/text/indent.py +6 -2
- omlish/typedvalues/values.py +0 -4
- {omlish-0.0.0.dev295.dist-info → omlish-0.0.0.dev297.dist-info}/METADATA +3 -1
- {omlish-0.0.0.dev295.dist-info → omlish-0.0.0.dev297.dist-info}/RECORD +30 -23
- {omlish-0.0.0.dev295.dist-info → omlish-0.0.0.dev297.dist-info}/WHEEL +0 -0
- {omlish-0.0.0.dev295.dist-info → omlish-0.0.0.dev297.dist-info}/entry_points.txt +0 -0
- {omlish-0.0.0.dev295.dist-info → omlish-0.0.0.dev297.dist-info}/licenses/LICENSE +0 -0
- {omlish-0.0.0.dev295.dist-info → omlish-0.0.0.dev297.dist-info}/top_level.txt +0 -0
omlish/dom/rendering.py
ADDED
@@ -0,0 +1,184 @@
|
|
1
|
+
import io
|
2
|
+
import textwrap
|
3
|
+
import typing as ta
|
4
|
+
|
5
|
+
from .. import check
|
6
|
+
from .. import dataclasses as dc
|
7
|
+
from .. import dispatch
|
8
|
+
from .. import lang
|
9
|
+
from .content import Dom
|
10
|
+
from .content import iter_content
|
11
|
+
|
12
|
+
|
13
|
+
if ta.TYPE_CHECKING:
|
14
|
+
import markupsafe as ms
|
15
|
+
|
16
|
+
_HAS_MARKUPSAFE = True
|
17
|
+
|
18
|
+
else:
|
19
|
+
ms = lang.proxy_import('markupsafe')
|
20
|
+
|
21
|
+
_HAS_MARKUPSAFE = lang.can_import('markupsafe')
|
22
|
+
|
23
|
+
|
24
|
+
##
|
25
|
+
|
26
|
+
|
27
|
+
@dc.dataclass()
|
28
|
+
class InvalidTagError(Exception):
|
29
|
+
pass
|
30
|
+
|
31
|
+
|
32
|
+
@dc.dataclass()
|
33
|
+
class StrForbiddenError(Exception):
|
34
|
+
pass
|
35
|
+
|
36
|
+
|
37
|
+
class Renderer:
|
38
|
+
def __init__(
|
39
|
+
self,
|
40
|
+
sb: io.StringIO | None,
|
41
|
+
*,
|
42
|
+
forbid_str: bool = False,
|
43
|
+
escape: ta.Callable[[str], str] | None = None,
|
44
|
+
indent: str | int | None = None,
|
45
|
+
indent_string_content: bool = False,
|
46
|
+
) -> None:
|
47
|
+
super().__init__()
|
48
|
+
|
49
|
+
if sb is None:
|
50
|
+
sb = io.StringIO()
|
51
|
+
self._sb = sb
|
52
|
+
|
53
|
+
self._forbid_str = forbid_str
|
54
|
+
self._escape_fn = escape
|
55
|
+
if isinstance(indent, int):
|
56
|
+
indent = ' ' * indent
|
57
|
+
self._indent_unit: str | None = indent
|
58
|
+
self._indent_string_content = indent_string_content
|
59
|
+
|
60
|
+
self._level = 0
|
61
|
+
self._indent_cache: dict[int, str] = {}
|
62
|
+
|
63
|
+
@classmethod
|
64
|
+
def render_to_str(cls, o: ta.Any, **kwargs: ta.Any) -> str:
|
65
|
+
sb = io.StringIO()
|
66
|
+
cls(sb, **kwargs).render(o)
|
67
|
+
return sb.getvalue()
|
68
|
+
|
69
|
+
#
|
70
|
+
|
71
|
+
def _escape(self, s: str) -> str:
|
72
|
+
if _HAS_MARKUPSAFE and isinstance(s, ms.Markup):
|
73
|
+
return s
|
74
|
+
if type(s) is not str:
|
75
|
+
raise TypeError(s)
|
76
|
+
if (fn := self._escape_fn) is None:
|
77
|
+
return s
|
78
|
+
return fn(s)
|
79
|
+
|
80
|
+
def _check_tag(self, s: str) -> str:
|
81
|
+
if self._escape(s) != s:
|
82
|
+
raise InvalidTagError(s)
|
83
|
+
return s
|
84
|
+
|
85
|
+
#
|
86
|
+
|
87
|
+
def _indent_str(self) -> str | None:
|
88
|
+
if not (s := self._indent_unit):
|
89
|
+
return None
|
90
|
+
try:
|
91
|
+
return self._indent_cache[self._level]
|
92
|
+
except KeyError:
|
93
|
+
pass
|
94
|
+
ls = self._indent_cache[self._level] = s * self._level
|
95
|
+
return ls
|
96
|
+
|
97
|
+
def _write_indent(self) -> None:
|
98
|
+
if (s := self._indent_str()):
|
99
|
+
self._sb.write(s)
|
100
|
+
|
101
|
+
#
|
102
|
+
|
103
|
+
@dispatch.method
|
104
|
+
def render(self, o: ta.Any) -> None:
|
105
|
+
raise TypeError(o)
|
106
|
+
|
107
|
+
#
|
108
|
+
|
109
|
+
def _write_string_content(self, s: str) -> None:
|
110
|
+
if self._indent_string_content and (ls := self._indent_str()):
|
111
|
+
s = textwrap.indent(s, ls)
|
112
|
+
self._sb.write(s)
|
113
|
+
|
114
|
+
@render.register # noqa
|
115
|
+
def _render_str(self, s: str) -> None:
|
116
|
+
if self._forbid_str:
|
117
|
+
raise StrForbiddenError(s)
|
118
|
+
self._write_string_content(s)
|
119
|
+
|
120
|
+
@render.register # noqa
|
121
|
+
def _render_sequence(self, l: ta.Sequence) -> None:
|
122
|
+
for e in l:
|
123
|
+
self.render(e)
|
124
|
+
|
125
|
+
#
|
126
|
+
|
127
|
+
if _HAS_MARKUPSAFE:
|
128
|
+
@render.register
|
129
|
+
def _render_markup(self, m: ms.Markup) -> None:
|
130
|
+
self._write_string_content(m)
|
131
|
+
|
132
|
+
#
|
133
|
+
|
134
|
+
def _render_tag(self, tag: str) -> None:
|
135
|
+
self._sb.write(self._check_tag(tag))
|
136
|
+
|
137
|
+
def _render_attr_key(self, k: str) -> None:
|
138
|
+
self._sb.write(self._check_tag(k))
|
139
|
+
|
140
|
+
def _render_attr_value(self, v: ta.Any) -> None:
|
141
|
+
self._sb.write('"')
|
142
|
+
self._sb.write(check.isinstance(v, str)) # FIXME
|
143
|
+
self._sb.write('"')
|
144
|
+
|
145
|
+
@render.register # noqa
|
146
|
+
def _render_dom(self, n: Dom) -> None:
|
147
|
+
self._write_indent()
|
148
|
+
|
149
|
+
self._sb.write('<')
|
150
|
+
self._render_tag(n.tag)
|
151
|
+
|
152
|
+
for k, v in (n.attrs or {}).items():
|
153
|
+
self._sb.write(' ')
|
154
|
+
self._render_attr_key(k)
|
155
|
+
if v is not None:
|
156
|
+
self._sb.write('=')
|
157
|
+
self._render_attr_value(v)
|
158
|
+
|
159
|
+
i = -1
|
160
|
+
for i, c in enumerate(iter_content(n.body)):
|
161
|
+
if not i:
|
162
|
+
self._sb.write('>')
|
163
|
+
|
164
|
+
if self._indent_unit:
|
165
|
+
self._sb.write('\n')
|
166
|
+
|
167
|
+
self._level += 1
|
168
|
+
self.render(c)
|
169
|
+
self._level -= 1
|
170
|
+
|
171
|
+
if i >= 0:
|
172
|
+
if self._indent_unit:
|
173
|
+
self._sb.write('\n')
|
174
|
+
self._write_indent()
|
175
|
+
|
176
|
+
self._sb.write('</')
|
177
|
+
self._render_tag(n.tag)
|
178
|
+
self._sb.write('>')
|
179
|
+
|
180
|
+
else:
|
181
|
+
self._sb.write(' />')
|
182
|
+
|
183
|
+
|
184
|
+
render = Renderer.render_to_str
|
omlish/math/__init__.py
CHANGED
@@ -0,0 +1,83 @@
|
|
1
|
+
from .bits import ( # noqa
|
2
|
+
get_bit,
|
3
|
+
get_bits,
|
4
|
+
set_bit,
|
5
|
+
set_bits,
|
6
|
+
)
|
7
|
+
|
8
|
+
from .c import ( # noqa
|
9
|
+
cdiv,
|
10
|
+
cmod,
|
11
|
+
)
|
12
|
+
|
13
|
+
from .fixed import ( # noqa
|
14
|
+
CheckedFixedWidthIntError,
|
15
|
+
OverflowFixedWidthIntError,
|
16
|
+
UnderflowFixedWidthIntError,
|
17
|
+
|
18
|
+
FixedWidthInt,
|
19
|
+
|
20
|
+
SignedInt,
|
21
|
+
UnsignedInt,
|
22
|
+
|
23
|
+
CheckedInt,
|
24
|
+
ClampedInt,
|
25
|
+
|
26
|
+
AnyInt8,
|
27
|
+
AnyInt16,
|
28
|
+
AnyInt32,
|
29
|
+
AnyInt64,
|
30
|
+
AnyInt128,
|
31
|
+
|
32
|
+
CheckedInt8,
|
33
|
+
CheckedInt16,
|
34
|
+
CheckedInt32,
|
35
|
+
CheckedInt64,
|
36
|
+
CheckedInt128,
|
37
|
+
|
38
|
+
CheckedUInt8,
|
39
|
+
CheckedUInt16,
|
40
|
+
CheckedUInt32,
|
41
|
+
CheckedUInt64,
|
42
|
+
CheckedUInt128,
|
43
|
+
|
44
|
+
ClampedInt8,
|
45
|
+
ClampedInt16,
|
46
|
+
ClampedInt32,
|
47
|
+
ClampedInt64,
|
48
|
+
ClampedInt128,
|
49
|
+
|
50
|
+
ClampedUInt8,
|
51
|
+
ClampedUInt16,
|
52
|
+
ClampedUInt32,
|
53
|
+
ClampedUInt64,
|
54
|
+
ClampedUInt128,
|
55
|
+
|
56
|
+
WrappedInt8,
|
57
|
+
WrappedInt16,
|
58
|
+
WrappedInt32,
|
59
|
+
WrappedInt64,
|
60
|
+
WrappedInt128,
|
61
|
+
|
62
|
+
WrappedUInt8,
|
63
|
+
WrappedUInt16,
|
64
|
+
WrappedUInt32,
|
65
|
+
WrappedUInt64,
|
66
|
+
WrappedUInt128,
|
67
|
+
)
|
68
|
+
|
69
|
+
from .floats import ( # noqa
|
70
|
+
isclose,
|
71
|
+
float_to_bytes,
|
72
|
+
bytes_to_float,
|
73
|
+
)
|
74
|
+
|
75
|
+
from .stats import ( # noqa
|
76
|
+
get_quantile,
|
77
|
+
|
78
|
+
Stats,
|
79
|
+
)
|
80
|
+
|
81
|
+
from .histogram import ( # noqa
|
82
|
+
SamplingHistogram,
|
83
|
+
)
|
omlish/math/bits.py
CHANGED
@@ -1,10 +1,3 @@
|
|
1
|
-
import functools
|
2
|
-
import typing as ta
|
3
|
-
|
4
|
-
|
5
|
-
##
|
6
|
-
|
7
|
-
|
8
1
|
def get_bit(bit: int, value: int) -> int:
|
9
2
|
return (value >> bit) & 1
|
10
3
|
|
@@ -22,149 +15,3 @@ def set_bit(bit: int, bit_value: int, value: int) -> int:
|
|
22
15
|
|
23
16
|
def set_bits(bits_from: int, num_bits: int, bits_value: int, value: int) -> int:
|
24
17
|
return value & ~(((1 << num_bits) - 1) << bits_from) | (bits_value << bits_from)
|
25
|
-
|
26
|
-
|
27
|
-
##
|
28
|
-
|
29
|
-
|
30
|
-
def _gen_scalar_proxy_method(name):
|
31
|
-
def inner(self, *args, **kwargs):
|
32
|
-
return self.__class__(orig(self, *args, **kwargs))
|
33
|
-
|
34
|
-
orig = getattr(int, name)
|
35
|
-
return functools.wraps(orig)(inner)
|
36
|
-
|
37
|
-
|
38
|
-
def _gen_tuple_proxy_method(name):
|
39
|
-
def inner(self, *args, **kwargs):
|
40
|
-
return tuple(map(self.__class__, orig(self, *args, **kwargs)))
|
41
|
-
|
42
|
-
orig = getattr(int, name)
|
43
|
-
return functools.wraps(orig)(inner)
|
44
|
-
|
45
|
-
|
46
|
-
class FixedWidthInt(int):
|
47
|
-
BITS: ta.ClassVar[int]
|
48
|
-
SIGNED: ta.ClassVar[bool]
|
49
|
-
|
50
|
-
MIN: ta.ClassVar[int]
|
51
|
-
MAX: ta.ClassVar[int]
|
52
|
-
|
53
|
-
MASK: ta.ClassVar[int]
|
54
|
-
|
55
|
-
def __init_subclass__(cls) -> None:
|
56
|
-
super().__init_subclass__()
|
57
|
-
|
58
|
-
if not isinstance(cls.BITS, int):
|
59
|
-
raise TypeError(cls.BITS)
|
60
|
-
|
61
|
-
if cls.SIGNED:
|
62
|
-
cls.MIN = -(1 << (cls.BITS - 1))
|
63
|
-
cls.MAX = (1 << (cls.BITS - 1)) - 1
|
64
|
-
else:
|
65
|
-
cls.MIN = 0
|
66
|
-
cls.MAX = (1 << cls.BITS) - 1
|
67
|
-
|
68
|
-
cls.MASK = (1 << cls.BITS) - 1
|
69
|
-
|
70
|
-
@classmethod
|
71
|
-
def clamp(cls, value: int) -> int:
|
72
|
-
return ((value - cls.MIN) & cls.MASK) + cls.MIN
|
73
|
-
|
74
|
-
def __new__(cls, value: int) -> 'FixedWidthInt':
|
75
|
-
return super().__new__(cls, cls.clamp(value)) # noqa
|
76
|
-
|
77
|
-
SCALAR_PROXY_METHODS = frozenset([
|
78
|
-
'__abs__',
|
79
|
-
'__add__',
|
80
|
-
'__and__',
|
81
|
-
'__floordiv__',
|
82
|
-
'__invert__',
|
83
|
-
'__lshift__',
|
84
|
-
'__mod__',
|
85
|
-
'__mul__',
|
86
|
-
'__neg__',
|
87
|
-
'__or__',
|
88
|
-
'__pos__',
|
89
|
-
'__pow__',
|
90
|
-
'__radd__',
|
91
|
-
'__rand__',
|
92
|
-
'__rfloordiv__',
|
93
|
-
'__rlshift__',
|
94
|
-
'__rmod__',
|
95
|
-
'__rmul__',
|
96
|
-
'__ror__',
|
97
|
-
'__rpow__',
|
98
|
-
'__rrshift__',
|
99
|
-
'__rshift__',
|
100
|
-
'__rsub__',
|
101
|
-
'__rtruediv__',
|
102
|
-
'__rxor__',
|
103
|
-
'__sub__',
|
104
|
-
'__truediv__',
|
105
|
-
'__xor__',
|
106
|
-
])
|
107
|
-
|
108
|
-
TUPLE_PROXY_METHODS = frozenset([
|
109
|
-
'__divmod__',
|
110
|
-
'__rdivmod__',
|
111
|
-
])
|
112
|
-
|
113
|
-
for _proxy_name in SCALAR_PROXY_METHODS:
|
114
|
-
locals()[_proxy_name] = _gen_scalar_proxy_method(_proxy_name)
|
115
|
-
for _proxy_name in TUPLE_PROXY_METHODS:
|
116
|
-
locals()[_proxy_name] = _gen_tuple_proxy_method(_proxy_name)
|
117
|
-
del _proxy_name
|
118
|
-
|
119
|
-
def __repr__(self) -> str:
|
120
|
-
return f'{self.__class__.__name__}({int(self)})'
|
121
|
-
|
122
|
-
|
123
|
-
class Int8(FixedWidthInt):
|
124
|
-
BITS = 8
|
125
|
-
SIGNED = True
|
126
|
-
|
127
|
-
|
128
|
-
class Int16(FixedWidthInt):
|
129
|
-
BITS = 16
|
130
|
-
SIGNED = True
|
131
|
-
|
132
|
-
|
133
|
-
class Int32(FixedWidthInt):
|
134
|
-
BITS = 32
|
135
|
-
SIGNED = True
|
136
|
-
|
137
|
-
|
138
|
-
class Int64(FixedWidthInt):
|
139
|
-
BITS = 64
|
140
|
-
SIGNED = True
|
141
|
-
|
142
|
-
|
143
|
-
class Int128(FixedWidthInt):
|
144
|
-
BITS = 128
|
145
|
-
SIGNED = True
|
146
|
-
|
147
|
-
|
148
|
-
class Uint8(FixedWidthInt):
|
149
|
-
BITS = 8
|
150
|
-
SIGNED = False
|
151
|
-
|
152
|
-
|
153
|
-
class Uint16(FixedWidthInt):
|
154
|
-
BITS = 16
|
155
|
-
SIGNED = False
|
156
|
-
|
157
|
-
|
158
|
-
class Uint32(FixedWidthInt):
|
159
|
-
BITS = 32
|
160
|
-
SIGNED = False
|
161
|
-
|
162
|
-
|
163
|
-
class Uint64(FixedWidthInt):
|
164
|
-
BITS = 64
|
165
|
-
SIGNED = False
|
166
|
-
|
167
|
-
|
168
|
-
class Uint128(FixedWidthInt):
|
169
|
-
BITS = 128
|
170
|
-
SIGNED = False
|
omlish/math/c.py
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
def cdiv(x: int, y: int) -> int:
|
2
|
+
"""https://python-history.blogspot.com/2010/08/why-pythons-integer-division-floors.html"""
|
3
|
+
|
4
|
+
if y == 0:
|
5
|
+
return 0
|
6
|
+
u = abs(x) // abs(y)
|
7
|
+
if (x < 0) ^ (y < 0):
|
8
|
+
u *= -1
|
9
|
+
return u
|
10
|
+
|
11
|
+
|
12
|
+
def cmod(x: int, y: int) -> int:
|
13
|
+
return x - (cdiv(x, y) * y)
|