omlish 0.0.0.dev425__py3-none-any.whl → 0.0.0.dev426__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 +2 -2
- omlish/c3.py +4 -1
- omlish/configs/processing/flattening.py +1 -1
- omlish/configs/processing/merging.py +8 -6
- omlish/dataclasses/impl/concerns/doc.py +1 -1
- omlish/diag/_pycharm/runhack.py +1 -1
- omlish/diag/procfs.py +2 -2
- omlish/formats/json/stream/lexing.py +63 -16
- omlish/formats/json/stream/parsing.py +1 -1
- omlish/formats/json/stream/utils.py +2 -2
- omlish/formats/logfmt.py +8 -2
- omlish/funcs/genmachine.py +1 -1
- omlish/http/sse.py +1 -1
- omlish/inject/impl/injector.py +1 -1
- omlish/inject/impl/multis.py +2 -2
- omlish/inject/impl/providers.py +0 -4
- omlish/inject/impl/proxy.py +0 -2
- omlish/inject/scopes.py +0 -4
- omlish/io/buffers.py +1 -1
- omlish/lang/__init__.py +23 -13
- omlish/lang/{attrs.py → attrstorage.py} +15 -15
- omlish/lang/cached/property.py +2 -2
- omlish/lang/classes/simple.py +26 -4
- omlish/lang/collections.py +1 -1
- omlish/lang/iterables.py +2 -2
- omlish/lifecycles/contextmanagers.py +1 -1
- omlish/lifecycles/controller.py +1 -1
- omlish/lite/asyncs.py +5 -0
- omlish/lite/attrops.py +332 -0
- omlish/lite/cached.py +1 -1
- omlish/lite/maybes.py +2 -0
- omlish/lite/strings.py +0 -7
- omlish/lite/timing.py +4 -1
- omlish/logs/all.py +4 -0
- omlish/logs/modules.py +10 -0
- omlish/logs/times.py +2 -5
- omlish/os/atomics.py +1 -1
- omlish/reflect/types.py +22 -0
- {omlish-0.0.0.dev425.dist-info → omlish-0.0.0.dev426.dist-info}/METADATA +2 -2
- {omlish-0.0.0.dev425.dist-info → omlish-0.0.0.dev426.dist-info}/RECORD +44 -44
- omlish/lite/logs.py +0 -4
- omlish/lite/reprs.py +0 -85
- {omlish-0.0.0.dev425.dist-info → omlish-0.0.0.dev426.dist-info}/WHEEL +0 -0
- {omlish-0.0.0.dev425.dist-info → omlish-0.0.0.dev426.dist-info}/entry_points.txt +0 -0
- {omlish-0.0.0.dev425.dist-info → omlish-0.0.0.dev426.dist-info}/licenses/LICENSE +0 -0
- {omlish-0.0.0.dev425.dist-info → omlish-0.0.0.dev426.dist-info}/top_level.txt +0 -0
omlish/lite/asyncs.py
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# ruff: noqa: UP045
|
1
2
|
import functools
|
2
3
|
import typing as ta
|
3
4
|
|
@@ -8,6 +9,10 @@ T = ta.TypeVar('T')
|
|
8
9
|
##
|
9
10
|
|
10
11
|
|
12
|
+
async def opt_await(aw: ta.Optional[ta.Awaitable[T]]) -> ta.Optional[T]:
|
13
|
+
return (await aw if aw is not None else None)
|
14
|
+
|
15
|
+
|
11
16
|
def as_async(fn: ta.Callable[..., T], *, wrap: bool = False) -> ta.Callable[..., ta.Awaitable[T]]:
|
12
17
|
async def inner(*args, **kwargs):
|
13
18
|
return fn(*args, **kwargs)
|
omlish/lite/attrops.py
ADDED
@@ -0,0 +1,332 @@
|
|
1
|
+
# ruff: noqa: UP006 UP007 UP045
|
2
|
+
# @omlish-lite
|
3
|
+
"""
|
4
|
+
TODO:
|
5
|
+
- dotted paths!
|
6
|
+
- per-attr repr transform / filter
|
7
|
+
- __ne__ ? cases where it still matters
|
8
|
+
- ordering ?
|
9
|
+
"""
|
10
|
+
import types # noqa
|
11
|
+
import typing as ta
|
12
|
+
|
13
|
+
|
14
|
+
T = ta.TypeVar('T')
|
15
|
+
|
16
|
+
|
17
|
+
##
|
18
|
+
|
19
|
+
|
20
|
+
@ta.final
|
21
|
+
class AttrOps(ta.Generic[T]):
|
22
|
+
@ta.final
|
23
|
+
class Attr:
|
24
|
+
def __init__(
|
25
|
+
self,
|
26
|
+
name: str,
|
27
|
+
*,
|
28
|
+
display: ta.Optional[str] = None,
|
29
|
+
|
30
|
+
repr: bool = True, # noqa
|
31
|
+
hash: bool = True, # noqa
|
32
|
+
eq: bool = True,
|
33
|
+
) -> None:
|
34
|
+
if '.' in name:
|
35
|
+
raise NotImplementedError('Dotted paths not yet supported')
|
36
|
+
if not name.isidentifier() or name.startswith('__'):
|
37
|
+
raise AttributeError(f'Invalid attr: {name!r}')
|
38
|
+
self._name = name
|
39
|
+
|
40
|
+
if display is None:
|
41
|
+
display = name[1:] if name.startswith('_') and len(name) > 1 else name
|
42
|
+
self._display = display
|
43
|
+
|
44
|
+
self._repr = repr
|
45
|
+
self._hash = hash
|
46
|
+
self._eq = eq
|
47
|
+
|
48
|
+
@classmethod
|
49
|
+
def of(
|
50
|
+
cls,
|
51
|
+
o: ta.Union[
|
52
|
+
str,
|
53
|
+
ta.Tuple[str, str],
|
54
|
+
'AttrOps.Attr',
|
55
|
+
],
|
56
|
+
) -> 'AttrOps.Attr':
|
57
|
+
if isinstance(o, AttrOps.Attr):
|
58
|
+
return o
|
59
|
+
elif isinstance(o, str):
|
60
|
+
return cls(o)
|
61
|
+
else:
|
62
|
+
name, disp = o
|
63
|
+
return cls(
|
64
|
+
name,
|
65
|
+
display=disp,
|
66
|
+
)
|
67
|
+
|
68
|
+
@property
|
69
|
+
def name(self) -> str:
|
70
|
+
return self._name
|
71
|
+
|
72
|
+
@property
|
73
|
+
def display(self) -> str:
|
74
|
+
return self._display
|
75
|
+
|
76
|
+
@property
|
77
|
+
def hash(self) -> bool:
|
78
|
+
return self._hash
|
79
|
+
|
80
|
+
@property
|
81
|
+
def eq(self) -> bool:
|
82
|
+
return self._eq
|
83
|
+
|
84
|
+
@ta.overload
|
85
|
+
def __init__(
|
86
|
+
self,
|
87
|
+
*attrs: ta.Sequence[ta.Union[
|
88
|
+
str,
|
89
|
+
ta.Tuple[str, str],
|
90
|
+
Attr,
|
91
|
+
]],
|
92
|
+
with_module: bool = False,
|
93
|
+
use_qualname: bool = False,
|
94
|
+
with_id: bool = False,
|
95
|
+
repr_filter: ta.Optional[ta.Callable[[ta.Any], bool]] = None,
|
96
|
+
recursive: bool = False,
|
97
|
+
subtypes_eq: bool = False,
|
98
|
+
) -> None:
|
99
|
+
...
|
100
|
+
|
101
|
+
@ta.overload
|
102
|
+
def __init__(
|
103
|
+
self,
|
104
|
+
attrs_fn: ta.Callable[[T], ta.Tuple[ta.Union[
|
105
|
+
ta.Any,
|
106
|
+
ta.Tuple[str, ta.Any],
|
107
|
+
Attr,
|
108
|
+
], ...]],
|
109
|
+
/,
|
110
|
+
*,
|
111
|
+
with_module: bool = False,
|
112
|
+
use_qualname: bool = False,
|
113
|
+
with_id: bool = False,
|
114
|
+
repr_filter: ta.Optional[ta.Callable[[ta.Any], bool]] = None,
|
115
|
+
recursive: bool = False,
|
116
|
+
subtypes_eq: bool = False,
|
117
|
+
) -> None:
|
118
|
+
...
|
119
|
+
|
120
|
+
def __init__(
|
121
|
+
self,
|
122
|
+
*args,
|
123
|
+
with_module=False,
|
124
|
+
use_qualname=False,
|
125
|
+
with_id=False,
|
126
|
+
repr_filter=None,
|
127
|
+
recursive=False,
|
128
|
+
subtypes_eq=False,
|
129
|
+
) -> None:
|
130
|
+
if args and len(args) == 1 and callable(args[0]):
|
131
|
+
self._attrs: ta.Sequence[AttrOps.Attr] = self._capture_attrs(args[0])
|
132
|
+
else:
|
133
|
+
self._attrs = list(map(AttrOps.Attr.of, args))
|
134
|
+
|
135
|
+
self._with_module: bool = with_module
|
136
|
+
self._use_qualname: bool = use_qualname
|
137
|
+
self._with_id: bool = with_id
|
138
|
+
self._repr_filter: ta.Optional[ta.Callable[[ta.Any], bool]] = repr_filter
|
139
|
+
self._recursive: bool = recursive
|
140
|
+
self._subtypes_eq: bool = subtypes_eq
|
141
|
+
|
142
|
+
@property
|
143
|
+
def attrs(self) -> ta.Sequence[Attr]:
|
144
|
+
return self._attrs
|
145
|
+
|
146
|
+
#
|
147
|
+
|
148
|
+
@ta.final
|
149
|
+
class _AttrCapturer:
|
150
|
+
def __init__(self, fn):
|
151
|
+
self.__fn = fn
|
152
|
+
|
153
|
+
def __getattr__(self, attr):
|
154
|
+
return self.__fn(self, attr)
|
155
|
+
|
156
|
+
@classmethod
|
157
|
+
def _capture_attrs(cls, fn: ta.Callable) -> ta.Sequence[Attr]:
|
158
|
+
def access(parent, attr):
|
159
|
+
dct[(ret := cls._AttrCapturer(access))] = (parent, attr)
|
160
|
+
return ret
|
161
|
+
|
162
|
+
dct: dict = {}
|
163
|
+
raw = fn(root := cls._AttrCapturer(access))
|
164
|
+
|
165
|
+
def rec(cap): # noqa
|
166
|
+
if cap is root:
|
167
|
+
return
|
168
|
+
parent, attr = dct[cap]
|
169
|
+
yield from rec(parent)
|
170
|
+
yield attr
|
171
|
+
|
172
|
+
attrs: ta.List[AttrOps.Attr] = []
|
173
|
+
for o in raw:
|
174
|
+
if isinstance(o, AttrOps.Attr):
|
175
|
+
attrs.append(o)
|
176
|
+
continue
|
177
|
+
|
178
|
+
if isinstance(o, tuple):
|
179
|
+
disp, cap, = o
|
180
|
+
else:
|
181
|
+
disp, cap = None, o
|
182
|
+
|
183
|
+
path = tuple(rec(cap))
|
184
|
+
|
185
|
+
attrs.append(AttrOps.Attr(
|
186
|
+
'.'.join(path),
|
187
|
+
display=disp,
|
188
|
+
))
|
189
|
+
|
190
|
+
return attrs
|
191
|
+
|
192
|
+
#
|
193
|
+
|
194
|
+
_repr: ta.Callable[[T], str]
|
195
|
+
|
196
|
+
@property
|
197
|
+
def repr(self) -> ta.Callable[[T], str]:
|
198
|
+
try:
|
199
|
+
return self._repr
|
200
|
+
except AttributeError:
|
201
|
+
pass
|
202
|
+
|
203
|
+
def _repr(o: T) -> str:
|
204
|
+
vs = ', '.join(
|
205
|
+
f'{a._display}={v!r}' # noqa
|
206
|
+
for a in self._attrs
|
207
|
+
if a._repr # noqa
|
208
|
+
for v in [getattr(o, a._name)] # noqa
|
209
|
+
if self._repr_filter is None or self._repr_filter(v)
|
210
|
+
)
|
211
|
+
|
212
|
+
return (
|
213
|
+
f'{o.__class__.__module__ + "." if self._with_module else ""}'
|
214
|
+
f'{o.__class__.__qualname__ if self._use_qualname else o.__class__.__name__}'
|
215
|
+
f'{("@" + hex(id(o))[2:]) if self._with_id else ""}'
|
216
|
+
f'({vs})'
|
217
|
+
)
|
218
|
+
|
219
|
+
if self._recursive:
|
220
|
+
_repr = self._reprlib().recursive_repr()(_repr)
|
221
|
+
|
222
|
+
self._repr = _repr
|
223
|
+
return _repr
|
224
|
+
|
225
|
+
_reprlib_: ta.ClassVar[ta.Any]
|
226
|
+
|
227
|
+
@classmethod
|
228
|
+
def _reprlib(cls) -> ta.Any:
|
229
|
+
try:
|
230
|
+
return cls._reprlib_
|
231
|
+
except AttributeError:
|
232
|
+
pass
|
233
|
+
|
234
|
+
import reprlib # noqa
|
235
|
+
|
236
|
+
cls._reprlib_ = reprlib
|
237
|
+
return reprlib
|
238
|
+
|
239
|
+
#
|
240
|
+
|
241
|
+
_hash: ta.Callable[[T], int]
|
242
|
+
|
243
|
+
@property
|
244
|
+
def hash(self) -> ta.Callable[[T], int]:
|
245
|
+
try:
|
246
|
+
return self._hash
|
247
|
+
except AttributeError:
|
248
|
+
pass
|
249
|
+
|
250
|
+
def _hash(o: T) -> int:
|
251
|
+
return hash(tuple(
|
252
|
+
getattr(o, a._name) # noqa
|
253
|
+
for a in self._attrs
|
254
|
+
if a._hash # noqa
|
255
|
+
))
|
256
|
+
|
257
|
+
self._hash = _hash
|
258
|
+
return _hash
|
259
|
+
|
260
|
+
#
|
261
|
+
|
262
|
+
_eq: ta.Callable[[T, ta.Any], ta.Union[bool, 'types.NotImplementedType']]
|
263
|
+
|
264
|
+
@property
|
265
|
+
def eq(self) -> ta.Callable[[T, ta.Any], ta.Union[bool, 'types.NotImplementedType']]:
|
266
|
+
try:
|
267
|
+
return self._eq
|
268
|
+
except AttributeError:
|
269
|
+
pass
|
270
|
+
|
271
|
+
def _eq(o: T, x: ta.Any) -> 'ta.Union[bool, types.NotImplementedType]':
|
272
|
+
if self._subtypes_eq:
|
273
|
+
if not isinstance(x, type(o)):
|
274
|
+
return NotImplemented
|
275
|
+
else:
|
276
|
+
if type(x) is not type(o):
|
277
|
+
return NotImplemented
|
278
|
+
|
279
|
+
return all(
|
280
|
+
getattr(o, a._name) == getattr(x, a._name) # noqa
|
281
|
+
for a in self._attrs
|
282
|
+
if a._eq # noqa
|
283
|
+
)
|
284
|
+
|
285
|
+
self._eq = _eq
|
286
|
+
return _eq
|
287
|
+
|
288
|
+
#
|
289
|
+
|
290
|
+
@property
|
291
|
+
def hash_eq(self) -> ta.Tuple[
|
292
|
+
ta.Callable[[T], int],
|
293
|
+
ta.Callable[[T, ta.Any], ta.Union[bool, 'types.NotImplementedType']],
|
294
|
+
]:
|
295
|
+
return (self.hash, self.eq)
|
296
|
+
|
297
|
+
@property
|
298
|
+
def repr_hash_eq(self) -> ta.Tuple[
|
299
|
+
ta.Callable[[T], str],
|
300
|
+
ta.Callable[[T], int],
|
301
|
+
ta.Callable[[T, ta.Any], ta.Union[bool, 'types.NotImplementedType']],
|
302
|
+
]:
|
303
|
+
return (self.repr, self.hash, self.eq)
|
304
|
+
|
305
|
+
#
|
306
|
+
|
307
|
+
def install(
|
308
|
+
self,
|
309
|
+
locals_dct: ta.MutableMapping[str, ta.Any],
|
310
|
+
*,
|
311
|
+
all: bool = False, # noqa
|
312
|
+
repr: bool = False, # noqa
|
313
|
+
hash: bool = False, # noqa
|
314
|
+
eq: bool = False,
|
315
|
+
) -> 'AttrOps[T]':
|
316
|
+
if repr or all:
|
317
|
+
locals_dct.update(__repr__=self.repr)
|
318
|
+
if hash or all:
|
319
|
+
locals_dct.update(__hash__=self.hash)
|
320
|
+
if eq or all:
|
321
|
+
locals_dct.update(__eq__=self.eq)
|
322
|
+
return self
|
323
|
+
|
324
|
+
|
325
|
+
attr_ops = AttrOps[ta.Any]
|
326
|
+
|
327
|
+
|
328
|
+
##
|
329
|
+
|
330
|
+
|
331
|
+
def attr_repr(obj: ta.Any, *attrs: str, **kwargs: ta.Any) -> str:
|
332
|
+
return AttrOps(*attrs, **kwargs).repr(obj)
|
omlish/lite/cached.py
CHANGED
@@ -21,7 +21,7 @@ class _AbstractCachedNullary:
|
|
21
21
|
def __call__(self, *args, **kwargs): # noqa
|
22
22
|
raise TypeError
|
23
23
|
|
24
|
-
def __get__(self, instance, owner): # noqa
|
24
|
+
def __get__(self, instance, owner=None): # noqa
|
25
25
|
bound = instance.__dict__[self._fn.__name__] = self.__class__(self._fn.__get__(instance, owner))
|
26
26
|
return bound
|
27
27
|
|
omlish/lite/maybes.py
CHANGED
@@ -148,6 +148,7 @@ class _Maybe(Maybe[T], Abstract):
|
|
148
148
|
return op and not sp
|
149
149
|
|
150
150
|
|
151
|
+
@ta.final
|
151
152
|
class _JustMaybe(_Maybe[T]):
|
152
153
|
__slots__ = ('_v', '_hash')
|
153
154
|
|
@@ -185,6 +186,7 @@ class _JustMaybe(_Maybe[T]):
|
|
185
186
|
)
|
186
187
|
|
187
188
|
|
189
|
+
@ta.final
|
188
190
|
class _EmptyMaybe(_Maybe[T]):
|
189
191
|
__slots__ = ()
|
190
192
|
|
omlish/lite/strings.py
CHANGED
@@ -73,13 +73,6 @@ def split_keep_delimiter(s, d):
|
|
73
73
|
##
|
74
74
|
|
75
75
|
|
76
|
-
def attr_repr(obj: ta.Any, *attrs: str) -> str:
|
77
|
-
return f'{type(obj).__name__}({", ".join(f"{attr}={getattr(obj, attr)!r}" for attr in attrs)})'
|
78
|
-
|
79
|
-
|
80
|
-
##
|
81
|
-
|
82
|
-
|
83
76
|
FORMAT_NUM_BYTES_SUFFIXES: ta.Sequence[str] = ['B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB']
|
84
77
|
|
85
78
|
|
omlish/lite/timing.py
CHANGED
omlish/logs/all.py
CHANGED
omlish/logs/modules.py
ADDED
omlish/logs/times.py
CHANGED
@@ -72,16 +72,13 @@ class UnexpectedLoggingStartTimeWarning(LoggingSetupWarning):
|
|
72
72
|
|
73
73
|
|
74
74
|
def _check_logging_start_time() -> None:
|
75
|
-
x
|
76
|
-
ns = time.time_ns()
|
77
|
-
|
78
|
-
if x > ns:
|
75
|
+
if (x := LoggingTimeFields.get_std_start_time_ns()) < (t := time.time()):
|
79
76
|
import warnings # noqa
|
80
77
|
|
81
78
|
warnings.warn(
|
82
79
|
f'Unexpected logging start time detected: '
|
83
80
|
f'get_std_start_time_ns={x}, '
|
84
|
-
f'time.
|
81
|
+
f'time.time()={t}',
|
85
82
|
UnexpectedLoggingStartTimeWarning,
|
86
83
|
)
|
87
84
|
|
omlish/os/atomics.py
CHANGED
omlish/reflect/types.py
CHANGED
@@ -407,6 +407,16 @@ class ReflectTypeError(TypeError):
|
|
407
407
|
pass
|
408
408
|
|
409
409
|
|
410
|
+
_TRIVIAL_TYPES: set[ta.Any] = {
|
411
|
+
bool,
|
412
|
+
int,
|
413
|
+
str,
|
414
|
+
float,
|
415
|
+
object,
|
416
|
+
type(None),
|
417
|
+
}
|
418
|
+
|
419
|
+
|
410
420
|
class Reflector:
|
411
421
|
def __init__(
|
412
422
|
self,
|
@@ -448,12 +458,24 @@ class Reflector:
|
|
448
458
|
if obj is ta.Any:
|
449
459
|
return ANY
|
450
460
|
|
461
|
+
##
|
462
|
+
# Trivial
|
463
|
+
|
464
|
+
try:
|
465
|
+
if obj in _TRIVIAL_TYPES:
|
466
|
+
return obj
|
467
|
+
except TypeError:
|
468
|
+
pass
|
469
|
+
|
451
470
|
##
|
452
471
|
# Already a Type?
|
453
472
|
|
454
473
|
if isinstance(obj, (ta.TypeVar, TypeInfo)): # noqa
|
455
474
|
return obj
|
456
475
|
|
476
|
+
##
|
477
|
+
# It's a type
|
478
|
+
|
457
479
|
oty = type(obj)
|
458
480
|
|
459
481
|
##
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: omlish
|
3
|
-
Version: 0.0.0.
|
3
|
+
Version: 0.0.0.dev426
|
4
4
|
Summary: omlish
|
5
5
|
Author: wrmsr
|
6
6
|
License-Expression: BSD-3-Clause
|
@@ -296,7 +296,7 @@ examples are:
|
|
296
296
|
- **wrapt** - For (optionally-enabled) injector circular proxies.
|
297
297
|
- **greenlet** - For some gnarly stuff like the
|
298
298
|
[sync<->async bridge](https://github.com/wrmsr/omlish/blob/master/omlish/asyncs/bridge.py) and the
|
299
|
-
[io trampoline](https://github.com/wrmsr/omlish/blob/master/
|
299
|
+
[io trampoline](https://github.com/wrmsr/omlish/blob/master/omextra/io/trampoline.py).
|
300
300
|
- **sqlalchemy** - Parts of the codebase use SQLAlchemy for db stuff, but it is being migrated away from in favor of the
|
301
301
|
internal api. It will however likely still remain as an optional dep for the api adapter.
|
302
302
|
|