omlish 0.0.0.dev424__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 +3 -3
- 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/dataclasses/impl/configs.py +2 -1
- omlish/diag/_pycharm/runhack.py +1 -1
- omlish/diag/procfs.py +2 -2
- omlish/formats/json/stream/lexing.py +69 -14
- omlish/formats/json/stream/parsing.py +1 -1
- omlish/formats/json/stream/utils.py +3 -0
- omlish/formats/json5/streams.py +22 -0
- 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 +26 -14
- omlish/lang/asyncs.py +12 -0
- 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/functions.py +0 -11
- omlish/lang/iterables.py +2 -2
- omlish/lang/lazyglobals.py +27 -5
- omlish/lang/maysync.py +2 -2
- omlish/lifecycles/contextmanagers.py +1 -2
- omlish/lifecycles/controller.py +1 -2
- omlish/lite/asyncs.py +20 -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 +6 -3
- omlish/logs/all.py +25 -32
- omlish/logs/base.py +248 -0
- omlish/logs/callers.py +21 -15
- omlish/logs/infos.py +105 -0
- omlish/logs/levels.py +64 -0
- omlish/logs/modules.py +10 -0
- omlish/logs/protocols.py +31 -0
- omlish/logs/standard.py +12 -11
- omlish/logs/std/adapters.py +41 -0
- omlish/logs/std/configs.py +29 -0
- omlish/logs/{filters.py → std/filters.py} +1 -1
- omlish/logs/{handlers.py → std/handlers.py} +1 -1
- omlish/logs/{json.py → std/json.py} +2 -2
- omlish/logs/{proxy.py → std/proxy.py} +3 -3
- omlish/logs/std/records.py +286 -0
- omlish/logs/times.py +86 -0
- omlish/logs/typed/bindings.py +24 -0
- omlish/logs/utils.py +60 -4
- omlish/logs/warnings.py +8 -0
- omlish/manifests/loading.py +1 -1
- omlish/os/atomics.py +1 -1
- omlish/os/journald.py +3 -3
- omlish/reflect/types.py +22 -0
- omlish/testing/pytest/plugins/skips.py +0 -4
- {omlish-0.0.0.dev424.dist-info → omlish-0.0.0.dev426.dist-info}/METADATA +2 -2
- {omlish-0.0.0.dev424.dist-info → omlish-0.0.0.dev426.dist-info}/RECORD +72 -114
- omlish/defs.py +0 -216
- omlish/dispatch/_dispatch2.py +0 -69
- omlish/dispatch/_dispatch3.py +0 -108
- omlish/dynamic.py +0 -219
- omlish/formats/json/Json.g4 +0 -77
- omlish/formats/json/_antlr/JsonLexer.py +0 -109
- omlish/formats/json/_antlr/JsonListener.py +0 -61
- omlish/formats/json/_antlr/JsonParser.py +0 -457
- omlish/formats/json/_antlr/JsonVisitor.py +0 -42
- omlish/io/trampoline.py +0 -289
- omlish/lite/logs.py +0 -4
- omlish/lite/reprs.py +0 -85
- omlish/logs/abc.py +0 -319
- omlish/logs/color.py +0 -27
- omlish/logs/configs.py +0 -29
- omlish/logs/protocol.py +0 -218
- omlish/logs/timing.py +0 -58
- omlish/specs/irc/__init__.py +0 -0
- omlish/specs/irc/messages/__init__.py +0 -0
- omlish/specs/irc/messages/base.py +0 -49
- omlish/specs/irc/messages/formats.py +0 -92
- omlish/specs/irc/messages/messages.py +0 -774
- omlish/specs/irc/messages/parsing.py +0 -98
- omlish/specs/irc/numerics/__init__.py +0 -0
- omlish/specs/irc/numerics/formats.py +0 -97
- omlish/specs/irc/numerics/numerics.py +0 -865
- omlish/specs/irc/numerics/types.py +0 -59
- omlish/specs/irc/protocol/LICENSE +0 -11
- omlish/specs/irc/protocol/__init__.py +0 -61
- omlish/specs/irc/protocol/consts.py +0 -6
- omlish/specs/irc/protocol/errors.py +0 -30
- omlish/specs/irc/protocol/message.py +0 -21
- omlish/specs/irc/protocol/nuh.py +0 -55
- omlish/specs/irc/protocol/parsing.py +0 -158
- omlish/specs/irc/protocol/rendering.py +0 -153
- omlish/specs/irc/protocol/tags.py +0 -102
- omlish/specs/irc/protocol/utils.py +0 -30
- omlish/specs/proto/Protobuf3.g4 +0 -396
- omlish/specs/proto/__init__.py +0 -0
- omlish/specs/proto/_antlr/Protobuf3Lexer.py +0 -340
- omlish/specs/proto/_antlr/Protobuf3Listener.py +0 -448
- omlish/specs/proto/_antlr/Protobuf3Parser.py +0 -3909
- omlish/specs/proto/_antlr/Protobuf3Visitor.py +0 -257
- omlish/specs/proto/_antlr/__init__.py +0 -0
- omlish/specs/proto/nodes.py +0 -54
- omlish/specs/proto/parsing.py +0 -97
- omlish/sql/parsing/Minisql.g4 +0 -292
- omlish/sql/parsing/__init__.py +0 -0
- omlish/sql/parsing/_antlr/MinisqlLexer.py +0 -322
- omlish/sql/parsing/_antlr/MinisqlListener.py +0 -511
- omlish/sql/parsing/_antlr/MinisqlParser.py +0 -3763
- omlish/sql/parsing/_antlr/MinisqlVisitor.py +0 -292
- omlish/sql/parsing/_antlr/__init__.py +0 -0
- omlish/sql/parsing/parsing.py +0 -119
- /omlish/{.manifests.json → .omlish-manifests.json} +0 -0
- /omlish/{formats/json/_antlr → logs/std}/__init__.py +0 -0
- /omlish/logs/{noisy.py → std/noisy.py} +0 -0
- {omlish-0.0.0.dev424.dist-info → omlish-0.0.0.dev426.dist-info}/WHEEL +0 -0
- {omlish-0.0.0.dev424.dist-info → omlish-0.0.0.dev426.dist-info}/entry_points.txt +0 -0
- {omlish-0.0.0.dev424.dist-info → omlish-0.0.0.dev426.dist-info}/licenses/LICENSE +0 -0
- {omlish-0.0.0.dev424.dist-info → omlish-0.0.0.dev426.dist-info}/top_level.txt +0 -0
omlish/lang/classes/simple.py
CHANGED
@@ -63,7 +63,6 @@ class Marker(NotInstantiable, metaclass=_MarkerMeta):
|
|
63
63
|
|
64
64
|
|
65
65
|
_SINGLETON_INSTANCE_ATTR = '__singleton_instance__'
|
66
|
-
_SINGLETON_LOCK = threading.RLock()
|
67
66
|
|
68
67
|
|
69
68
|
def _set_singleton_instance(inst):
|
@@ -85,7 +84,24 @@ def _set_singleton_instance(inst):
|
|
85
84
|
return inst
|
86
85
|
|
87
86
|
|
88
|
-
class
|
87
|
+
class _AnySingleton:
|
88
|
+
def __init__(self) -> None:
|
89
|
+
try:
|
90
|
+
type(self).__dict__[_SINGLETON_INSTANCE_ATTR]
|
91
|
+
except KeyError:
|
92
|
+
pass
|
93
|
+
else:
|
94
|
+
raise TypeError(f'Must not re-instantiate singleton {type(self)}')
|
95
|
+
|
96
|
+
super().__init__()
|
97
|
+
|
98
|
+
@ta.final
|
99
|
+
def __reduce__(self):
|
100
|
+
return (type(self), ())
|
101
|
+
|
102
|
+
|
103
|
+
class Singleton(_AnySingleton):
|
104
|
+
@ta.final
|
89
105
|
def __new__(cls):
|
90
106
|
return cls.__dict__[_SINGLETON_INSTANCE_ATTR]
|
91
107
|
|
@@ -95,15 +111,21 @@ class Singleton:
|
|
95
111
|
_set_singleton_instance(super().__new__(cls)) # noqa
|
96
112
|
|
97
113
|
|
98
|
-
|
114
|
+
_LAZY_SINGLETON_LOCK = threading.RLock()
|
115
|
+
|
116
|
+
|
117
|
+
class LazySingleton(_AnySingleton):
|
118
|
+
@ta.final
|
99
119
|
def __new__(cls):
|
100
120
|
try:
|
101
121
|
return cls.__dict__[_SINGLETON_INSTANCE_ATTR]
|
102
122
|
except KeyError:
|
103
123
|
pass
|
104
|
-
|
124
|
+
|
125
|
+
with _LAZY_SINGLETON_LOCK:
|
105
126
|
try:
|
106
127
|
return cls.__dict__[_SINGLETON_INSTANCE_ATTR]
|
107
128
|
except KeyError:
|
108
129
|
pass
|
130
|
+
|
109
131
|
return _set_singleton_instance(super().__new__(cls))
|
omlish/lang/collections.py
CHANGED
@@ -9,7 +9,7 @@ V = ta.TypeVar('V')
|
|
9
9
|
##
|
10
10
|
|
11
11
|
|
12
|
-
def yield_dict_init(*args: ta.Any, **kwargs: ta.Any) -> ta.
|
12
|
+
def yield_dict_init(*args: ta.Any, **kwargs: ta.Any) -> ta.Iterator[tuple[ta.Any, ta.Any]]:
|
13
13
|
if len(args) > 1:
|
14
14
|
raise TypeError
|
15
15
|
|
omlish/lang/functions.py
CHANGED
@@ -167,17 +167,6 @@ def void(*args: ta.Any, **kwargs: ta.Any) -> ta.NoReturn:
|
|
167
167
|
##
|
168
168
|
|
169
169
|
|
170
|
-
def as_async(fn: ta.Callable[P, T]) -> ta.Callable[P, ta.Awaitable[T]]:
|
171
|
-
@functools.wraps(fn)
|
172
|
-
async def inner(*args, **kwargs):
|
173
|
-
return fn(*args, **kwargs)
|
174
|
-
|
175
|
-
return inner
|
176
|
-
|
177
|
-
|
178
|
-
##
|
179
|
-
|
180
|
-
|
181
170
|
_MISSING = object()
|
182
171
|
|
183
172
|
|
omlish/lang/iterables.py
CHANGED
@@ -46,14 +46,14 @@ def chunk(n: int, iterable: ta.Iterable[T], strict: bool = False) -> ta.Iterator
|
|
46
46
|
return iterator
|
47
47
|
|
48
48
|
|
49
|
-
def interleave(vs: ta.Iterable[T], d: T) -> ta.
|
49
|
+
def interleave(vs: ta.Iterable[T], d: T) -> ta.Iterator[T]:
|
50
50
|
for i, v in enumerate(vs):
|
51
51
|
if i:
|
52
52
|
yield d
|
53
53
|
yield v
|
54
54
|
|
55
55
|
|
56
|
-
def renumerate(it: ta.Iterable[T]) -> ta.
|
56
|
+
def renumerate(it: ta.Iterable[T]) -> ta.Iterator[tuple[T, int]]:
|
57
57
|
return ((e, i) for i, e in enumerate(it))
|
58
58
|
|
59
59
|
|
omlish/lang/lazyglobals.py
CHANGED
@@ -4,6 +4,17 @@ import typing as ta
|
|
4
4
|
##
|
5
5
|
|
6
6
|
|
7
|
+
class AmbiguousLazyGlobalsFallbackError(Exception):
|
8
|
+
def __init__(self, attr: str, fallbacks: list[ta.Callable[[str], ta.Any]]) -> None:
|
9
|
+
super().__init__()
|
10
|
+
|
11
|
+
self.attr = attr
|
12
|
+
self.fallbacks = fallbacks
|
13
|
+
|
14
|
+
def __repr__(self) -> str:
|
15
|
+
return f'{self.__class__.__name__}({self.attr!r}, {self.fallbacks!r})'
|
16
|
+
|
17
|
+
|
7
18
|
class LazyGlobals:
|
8
19
|
def __init__(
|
9
20
|
self,
|
@@ -17,6 +28,7 @@ class LazyGlobals:
|
|
17
28
|
self._update_globals = update_globals
|
18
29
|
|
19
30
|
self._attr_fns: dict[str, ta.Callable[[], ta.Any]] = {}
|
31
|
+
self._fallback_fns: list[ta.Callable[[str], ta.Callable[[], ta.Any]]] = []
|
20
32
|
|
21
33
|
@classmethod
|
22
34
|
def install(cls, globals: ta.MutableMapping[str, ta.Any]) -> 'LazyGlobals': # noqa
|
@@ -42,13 +54,23 @@ class LazyGlobals:
|
|
42
54
|
self._attr_fns[attr] = fn
|
43
55
|
return self
|
44
56
|
|
57
|
+
def add_fallback_fn(self, fn: ta.Callable[[str], ta.Callable[[], ta.Any]]) -> 'LazyGlobals':
|
58
|
+
self._fallback_fns.append(fn)
|
59
|
+
return self
|
60
|
+
|
45
61
|
def get(self, attr: str) -> ta.Any:
|
46
|
-
|
47
|
-
fn = self._attr_fns[attr]
|
48
|
-
except KeyError:
|
49
|
-
raise AttributeError(attr) from None
|
62
|
+
val: ta.Any
|
50
63
|
|
51
|
-
|
64
|
+
if (attr_fn := self._attr_fns.get(attr)) is not None:
|
65
|
+
val = attr_fn()
|
66
|
+
|
67
|
+
elif (fallbacks := [(fb_fn, fb_fn(attr)) for fb_fn in self._fallback_fns]):
|
68
|
+
if len(fallbacks) > 1:
|
69
|
+
raise AmbiguousLazyGlobalsFallbackError(attr, [fb_fn for fb_fn, _ in fallbacks])
|
70
|
+
[val] = fallbacks
|
71
|
+
|
72
|
+
else:
|
73
|
+
raise AttributeError(attr)
|
52
74
|
|
53
75
|
if self._update_globals and self._globals is not None:
|
54
76
|
self._globals[attr] = val
|
omlish/lang/maysync.py
CHANGED
@@ -3,7 +3,7 @@ import typing as ta
|
|
3
3
|
from ..lite.maysync import MaysyncFn
|
4
4
|
from ..lite.maysync import MaysyncGeneratorFn
|
5
5
|
from ..lite.maysync import make_maysync as _make_maysync
|
6
|
-
from .
|
6
|
+
from .asyncs import as_async
|
7
7
|
|
8
8
|
|
9
9
|
T = ta.TypeVar('T')
|
@@ -68,5 +68,5 @@ def make_maysync_from_sync(
|
|
68
68
|
) -> ta.Callable[P, ta.Awaitable[T]]:
|
69
69
|
return _make_maysync(
|
70
70
|
s,
|
71
|
-
a if a is not None else as_async(s),
|
71
|
+
a if a is not None else as_async(s, wrap=True),
|
72
72
|
)
|
@@ -2,7 +2,6 @@ import types
|
|
2
2
|
import typing as ta
|
3
3
|
|
4
4
|
from .. import dataclasses as dc
|
5
|
-
from .. import defs
|
6
5
|
from .. import lang
|
7
6
|
from .base import Lifecycle
|
8
7
|
from .controller import LifecycleController
|
@@ -37,7 +36,7 @@ class LifecycleContextManager(ta.Generic[LifecycleT]):
|
|
37
36
|
self._lifecycle = lifecycle
|
38
37
|
self._controller = lifecycle if isinstance(lifecycle, LifecycleController) else LifecycleController(lifecycle)
|
39
38
|
|
40
|
-
|
39
|
+
__repr__ = lang.attr_ops('lifecycle', 'state').repr
|
41
40
|
|
42
41
|
@property
|
43
42
|
def lifecycle(self) -> LifecycleT:
|
omlish/lifecycles/controller.py
CHANGED
@@ -2,7 +2,6 @@ import abc
|
|
2
2
|
import typing as ta
|
3
3
|
|
4
4
|
from .. import check
|
5
|
-
from .. import defs
|
6
5
|
from .. import lang
|
7
6
|
from .base import AnyLifecycle # noqa
|
8
7
|
from .base import Lifecycle # noqa
|
@@ -48,7 +47,7 @@ class AnyLifecycleController(AnyLifecycle[R], lang.Abstract, ta.Generic[AnyLifec
|
|
48
47
|
self._state = LifecycleStates.NEW
|
49
48
|
self._listeners: list[AnyLifecycleListener[AnyLifecycleT, R]] = []
|
50
49
|
|
51
|
-
|
50
|
+
__repr__ = lang.attr_ops('lifecycle', 'state').repr
|
52
51
|
|
53
52
|
@property
|
54
53
|
def lifecycle(self) -> AnyLifecycleT:
|
omlish/lite/asyncs.py
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
# ruff: noqa: UP045
|
2
|
+
import functools
|
3
|
+
import typing as ta
|
4
|
+
|
5
|
+
|
6
|
+
T = ta.TypeVar('T')
|
7
|
+
|
8
|
+
|
9
|
+
##
|
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
|
+
|
16
|
+
def as_async(fn: ta.Callable[..., T], *, wrap: bool = False) -> ta.Callable[..., ta.Awaitable[T]]:
|
17
|
+
async def inner(*args, **kwargs):
|
18
|
+
return fn(*args, **kwargs)
|
19
|
+
|
20
|
+
return functools.wraps(fn)(inner) if wrap else inner
|
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
@@ -1,6 +1,9 @@
|
|
1
|
-
from ..logs.
|
2
|
-
from ..logs.
|
3
|
-
from .
|
1
|
+
from ..logs.modules import get_module_logger
|
2
|
+
from ..logs.utils import LogTimingContext
|
3
|
+
from ..logs.utils import log_timing_context
|
4
|
+
|
5
|
+
|
6
|
+
log = get_module_logger(globals()) # noqa
|
4
7
|
|
5
8
|
|
6
9
|
LogTimingContext.DEFAULT_LOG = log
|