omlish 0.0.0.dev5__py3-none-any.whl → 0.0.0.dev7__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.
Potentially problematic release.
This version of omlish might be problematic. Click here for more details.
- omlish/__about__.py +109 -5
- omlish/__init__.py +0 -8
- omlish/asyncs/__init__.py +9 -9
- omlish/asyncs/anyio.py +123 -19
- omlish/asyncs/asyncio.py +23 -0
- omlish/asyncs/asyncs.py +9 -6
- omlish/asyncs/bridge.py +316 -0
- omlish/asyncs/trio_asyncio.py +7 -3
- omlish/bootstrap.py +737 -0
- omlish/check.py +1 -1
- omlish/collections/__init__.py +5 -0
- omlish/collections/exceptions.py +2 -0
- omlish/collections/identity.py +7 -0
- omlish/collections/utils.py +38 -9
- omlish/configs/strings.py +96 -0
- omlish/dataclasses/__init__.py +16 -0
- omlish/dataclasses/impl/copy.py +30 -0
- omlish/dataclasses/impl/descriptors.py +95 -0
- omlish/dataclasses/impl/exceptions.py +6 -0
- omlish/dataclasses/impl/fields.py +24 -25
- omlish/dataclasses/impl/init.py +4 -2
- omlish/dataclasses/impl/main.py +2 -0
- omlish/dataclasses/impl/reflect.py +1 -1
- omlish/dataclasses/utils.py +67 -0
- omlish/{lang/datetimes.py → datetimes.py} +8 -4
- omlish/diag/__init__.py +4 -0
- omlish/diag/procfs.py +2 -2
- omlish/{testing → diag}/pydevd.py +35 -0
- omlish/diag/threads.py +131 -48
- omlish/dispatch/_dispatch2.py +65 -0
- omlish/dispatch/_dispatch3.py +104 -0
- omlish/docker.py +16 -1
- omlish/fnpairs.py +11 -4
- omlish/formats/__init__.py +0 -0
- omlish/{configs → formats}/dotenv.py +15 -24
- omlish/{json.py → formats/json.py} +2 -1
- omlish/formats/yaml.py +223 -0
- omlish/graphs/trees.py +1 -1
- omlish/http/asgi.py +2 -1
- omlish/http/collections.py +15 -0
- omlish/http/consts.py +22 -1
- omlish/http/sessions.py +10 -3
- omlish/inject/__init__.py +49 -17
- omlish/inject/binder.py +185 -5
- omlish/inject/bindings.py +3 -36
- omlish/inject/eagers.py +2 -8
- omlish/inject/elements.py +31 -10
- omlish/inject/exceptions.py +1 -1
- omlish/inject/impl/elements.py +37 -12
- omlish/inject/impl/injector.py +72 -25
- omlish/inject/impl/inspect.py +33 -5
- omlish/inject/impl/origins.py +77 -0
- omlish/inject/impl/{private.py → privates.py} +2 -2
- omlish/inject/impl/scopes.py +6 -2
- omlish/inject/injector.py +8 -4
- omlish/inject/inspect.py +18 -0
- omlish/inject/keys.py +8 -14
- omlish/inject/listeners.py +26 -0
- omlish/inject/managed.py +76 -10
- omlish/inject/multis.py +68 -18
- omlish/inject/origins.py +30 -0
- omlish/inject/overrides.py +5 -4
- omlish/inject/{private.py → privates.py} +6 -10
- omlish/inject/providers.py +12 -85
- omlish/inject/scopes.py +13 -6
- omlish/inject/types.py +3 -1
- omlish/inject/utils.py +18 -0
- omlish/iterators.py +69 -2
- omlish/lang/__init__.py +24 -9
- omlish/lang/cached.py +2 -2
- omlish/lang/classes/restrict.py +12 -1
- omlish/lang/classes/simple.py +18 -8
- omlish/lang/contextmanagers.py +13 -4
- omlish/lang/descriptors.py +132 -1
- omlish/lang/functions.py +8 -28
- omlish/lang/imports.py +67 -0
- omlish/lang/iterables.py +60 -1
- omlish/lang/maybes.py +3 -0
- omlish/lang/objects.py +38 -0
- omlish/lang/strings.py +25 -0
- omlish/lang/sys.py +9 -0
- omlish/lang/typing.py +42 -0
- omlish/lifecycles/__init__.py +34 -0
- omlish/lifecycles/abstract.py +43 -0
- omlish/lifecycles/base.py +51 -0
- omlish/lifecycles/contextmanagers.py +74 -0
- omlish/lifecycles/controller.py +116 -0
- omlish/lifecycles/manager.py +161 -0
- omlish/lifecycles/states.py +43 -0
- omlish/lifecycles/transitions.py +64 -0
- omlish/lite/__init__.py +1 -0
- omlish/lite/cached.py +18 -0
- omlish/lite/check.py +29 -0
- omlish/lite/contextmanagers.py +18 -0
- omlish/lite/json.py +30 -0
- omlish/lite/logs.py +52 -0
- omlish/lite/marshal.py +316 -0
- omlish/lite/reflect.py +49 -0
- omlish/lite/runtime.py +18 -0
- omlish/lite/secrets.py +19 -0
- omlish/lite/strings.py +25 -0
- omlish/lite/subprocesses.py +112 -0
- omlish/logs/configs.py +15 -2
- omlish/logs/formatters.py +7 -2
- omlish/marshal/__init__.py +32 -0
- omlish/marshal/any.py +5 -5
- omlish/marshal/base.py +27 -11
- omlish/marshal/base64.py +24 -9
- omlish/marshal/dataclasses.py +34 -28
- omlish/marshal/datetimes.py +74 -18
- omlish/marshal/enums.py +14 -8
- omlish/marshal/exceptions.py +11 -1
- omlish/marshal/factories.py +59 -74
- omlish/marshal/forbidden.py +35 -0
- omlish/marshal/global_.py +11 -4
- omlish/marshal/iterables.py +21 -24
- omlish/marshal/mappings.py +23 -26
- omlish/marshal/naming.py +4 -0
- omlish/marshal/numbers.py +51 -0
- omlish/marshal/objects.py +1 -0
- omlish/marshal/optionals.py +11 -12
- omlish/marshal/polymorphism.py +86 -21
- omlish/marshal/primitives.py +4 -5
- omlish/marshal/standard.py +13 -8
- omlish/marshal/uuids.py +4 -5
- omlish/matchfns.py +218 -0
- omlish/os.py +64 -0
- omlish/reflect/__init__.py +39 -0
- omlish/reflect/isinstance.py +38 -0
- omlish/reflect/ops.py +84 -0
- omlish/reflect/subst.py +110 -0
- omlish/reflect/types.py +275 -0
- omlish/secrets/__init__.py +23 -0
- omlish/secrets/crypto.py +132 -0
- omlish/secrets/marshal.py +70 -0
- omlish/secrets/openssl.py +207 -0
- omlish/secrets/passwords.py +120 -0
- omlish/secrets/secrets.py +299 -0
- omlish/secrets/subprocesses.py +42 -0
- omlish/sql/dbs.py +7 -6
- omlish/sql/duckdb.py +136 -0
- omlish/sql/exprs.py +12 -0
- omlish/sql/secrets.py +10 -0
- omlish/sql/sqlean.py +17 -0
- omlish/term.py +2 -2
- omlish/testing/pytest/__init__.py +3 -2
- omlish/testing/pytest/inject/harness.py +3 -3
- omlish/testing/pytest/marks.py +4 -7
- omlish/testing/pytest/plugins/__init__.py +1 -0
- omlish/testing/pytest/plugins/asyncs.py +136 -0
- omlish/testing/pytest/plugins/pydevd.py +1 -1
- omlish/testing/pytest/plugins/switches.py +54 -19
- omlish/text/glyphsplit.py +97 -0
- omlish-0.0.0.dev7.dist-info/METADATA +50 -0
- omlish-0.0.0.dev7.dist-info/RECORD +268 -0
- {omlish-0.0.0.dev5.dist-info → omlish-0.0.0.dev7.dist-info}/WHEEL +1 -1
- omlish/reflect.py +0 -355
- omlish-0.0.0.dev5.dist-info/METADATA +0 -34
- omlish-0.0.0.dev5.dist-info/RECORD +0 -212
- /omlish/{asyncs/futures.py → concurrent.py} +0 -0
- /omlish/{configs → formats}/props.py +0 -0
- {omlish-0.0.0.dev5.dist-info → omlish-0.0.0.dev7.dist-info}/LICENSE +0 -0
- {omlish-0.0.0.dev5.dist-info → omlish-0.0.0.dev7.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import typing as ta
|
|
2
|
+
|
|
3
|
+
from .. import check
|
|
4
|
+
from .. import collections as col
|
|
5
|
+
from .. import dataclasses as dc
|
|
6
|
+
from .. import lang
|
|
7
|
+
from .abstract import AbstractLifecycle
|
|
8
|
+
from .base import Lifecycle
|
|
9
|
+
from .controller import LifecycleController
|
|
10
|
+
from .states import LifecycleState
|
|
11
|
+
from .states import LifecycleStateError
|
|
12
|
+
from .states import LifecycleStates
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class LifecycleManager(AbstractLifecycle):
|
|
16
|
+
|
|
17
|
+
@dc.dataclass(frozen=True)
|
|
18
|
+
class Entry(lang.Final):
|
|
19
|
+
controller: LifecycleController
|
|
20
|
+
dependencies: ta.MutableSet['LifecycleManager.Entry'] = dc.field(default_factory=col.IdentitySet)
|
|
21
|
+
dependents: ta.MutableSet['LifecycleManager.Entry'] = dc.field(default_factory=col.IdentitySet)
|
|
22
|
+
|
|
23
|
+
def __init__(
|
|
24
|
+
self,
|
|
25
|
+
*,
|
|
26
|
+
lock: lang.DefaultLockable = None,
|
|
27
|
+
) -> None:
|
|
28
|
+
super().__init__()
|
|
29
|
+
|
|
30
|
+
self._lock = lang.default_lock(lock, False)
|
|
31
|
+
|
|
32
|
+
self._entries_by_lifecycle: ta.MutableMapping[Lifecycle, LifecycleManager.Entry] = col.IdentityKeyDict()
|
|
33
|
+
|
|
34
|
+
self._controller = LifecycleController(self._lifecycle, lock=self._lock)
|
|
35
|
+
|
|
36
|
+
@property
|
|
37
|
+
def controller(self) -> LifecycleController:
|
|
38
|
+
return self._controller
|
|
39
|
+
|
|
40
|
+
@property
|
|
41
|
+
def state(self) -> LifecycleState:
|
|
42
|
+
return self._controller.state
|
|
43
|
+
|
|
44
|
+
@staticmethod
|
|
45
|
+
def _get_controller(lifecycle: Lifecycle) -> LifecycleController:
|
|
46
|
+
if isinstance(lifecycle, LifecycleController):
|
|
47
|
+
return lifecycle
|
|
48
|
+
# elif isinstance(lifecycle, AbstractLifecycle):
|
|
49
|
+
# return lifecycle.lifecycle_controller
|
|
50
|
+
elif isinstance(lifecycle, Lifecycle):
|
|
51
|
+
return LifecycleController(lifecycle)
|
|
52
|
+
else:
|
|
53
|
+
raise TypeError(lifecycle)
|
|
54
|
+
|
|
55
|
+
def _add_internal(self, lifecycle: Lifecycle, dependencies: ta.Iterable[Lifecycle]) -> Entry:
|
|
56
|
+
check.state(self.state < LifecycleStates.STOPPING and not self.state.is_failed)
|
|
57
|
+
|
|
58
|
+
check.isinstance(lifecycle, Lifecycle)
|
|
59
|
+
try:
|
|
60
|
+
entry = self._entries_by_lifecycle[lifecycle]
|
|
61
|
+
except KeyError:
|
|
62
|
+
controller = self._get_controller(lifecycle)
|
|
63
|
+
entry = self._entries_by_lifecycle[lifecycle] = LifecycleManager.Entry(controller)
|
|
64
|
+
|
|
65
|
+
for dep in dependencies:
|
|
66
|
+
check.isinstance(dep, Lifecycle)
|
|
67
|
+
dep_entry = self._add_internal(dep, [])
|
|
68
|
+
entry.dependencies.add(dep_entry)
|
|
69
|
+
dep_entry.dependents.add(entry)
|
|
70
|
+
|
|
71
|
+
return entry
|
|
72
|
+
|
|
73
|
+
def add(
|
|
74
|
+
self,
|
|
75
|
+
lifecycle: Lifecycle,
|
|
76
|
+
dependencies: ta.Iterable[Lifecycle] = (),
|
|
77
|
+
) -> Entry:
|
|
78
|
+
check.state(self.state < LifecycleStates.STOPPING and not self.state.is_failed)
|
|
79
|
+
|
|
80
|
+
with self._lock():
|
|
81
|
+
entry = self._add_internal(lifecycle, dependencies)
|
|
82
|
+
|
|
83
|
+
if self.state >= LifecycleStates.CONSTRUCTING:
|
|
84
|
+
def rec(e):
|
|
85
|
+
if e.controller.state < LifecycleStates.CONSTRUCTED:
|
|
86
|
+
for dep in e.dependencies:
|
|
87
|
+
rec(dep)
|
|
88
|
+
e.controller.lifecycle_construct()
|
|
89
|
+
rec(entry)
|
|
90
|
+
|
|
91
|
+
if self.state >= LifecycleStates.STARTING:
|
|
92
|
+
def rec(e):
|
|
93
|
+
if e.controller.state < LifecycleStates.STARTED:
|
|
94
|
+
for dep in e.dependencies:
|
|
95
|
+
rec(dep)
|
|
96
|
+
e.controller.lifecycle_start()
|
|
97
|
+
rec(entry)
|
|
98
|
+
|
|
99
|
+
return entry
|
|
100
|
+
|
|
101
|
+
##
|
|
102
|
+
|
|
103
|
+
@ta.override
|
|
104
|
+
def _lifecycle_construct(self) -> None:
|
|
105
|
+
def rec(entry: LifecycleManager.Entry) -> None:
|
|
106
|
+
for dep in entry.dependencies:
|
|
107
|
+
rec(dep)
|
|
108
|
+
|
|
109
|
+
if entry.controller.state.is_failed:
|
|
110
|
+
raise LifecycleStateError(entry.controller)
|
|
111
|
+
|
|
112
|
+
if entry.controller.state < LifecycleStates.CONSTRUCTED:
|
|
113
|
+
entry.controller.lifecycle_construct()
|
|
114
|
+
|
|
115
|
+
for entry in self._entries_by_lifecycle.values():
|
|
116
|
+
rec(entry)
|
|
117
|
+
|
|
118
|
+
@ta.override
|
|
119
|
+
def _lifecycle_start(self) -> None:
|
|
120
|
+
def rec(entry: LifecycleManager.Entry) -> None:
|
|
121
|
+
for dep in entry.dependencies:
|
|
122
|
+
rec(dep)
|
|
123
|
+
|
|
124
|
+
if entry.controller.state.is_failed:
|
|
125
|
+
raise LifecycleStateError(entry.controller)
|
|
126
|
+
|
|
127
|
+
if entry.controller.state < LifecycleStates.CONSTRUCTED:
|
|
128
|
+
entry.controller.lifecycle_construct()
|
|
129
|
+
|
|
130
|
+
if entry.controller.state < LifecycleStates.STARTED:
|
|
131
|
+
entry.controller.lifecycle_start()
|
|
132
|
+
|
|
133
|
+
for entry in self._entries_by_lifecycle.values():
|
|
134
|
+
rec(entry)
|
|
135
|
+
|
|
136
|
+
@ta.override
|
|
137
|
+
def _lifecycle_stop(self) -> None:
|
|
138
|
+
def rec(entry: LifecycleManager.Entry) -> None:
|
|
139
|
+
for dep in entry.dependents:
|
|
140
|
+
rec(dep)
|
|
141
|
+
|
|
142
|
+
if entry.controller.state.is_failed:
|
|
143
|
+
raise LifecycleStateError(entry.controller)
|
|
144
|
+
|
|
145
|
+
if entry.controller.state is LifecycleStates.STARTED:
|
|
146
|
+
entry.controller.lifecycle_stop()
|
|
147
|
+
|
|
148
|
+
for entry in self._entries_by_lifecycle.values():
|
|
149
|
+
rec(entry)
|
|
150
|
+
|
|
151
|
+
@ta.override
|
|
152
|
+
def _lifecycle_destroy(self) -> None:
|
|
153
|
+
def rec(entry: LifecycleManager.Entry) -> None:
|
|
154
|
+
for dep in entry.dependents:
|
|
155
|
+
rec(dep)
|
|
156
|
+
|
|
157
|
+
if entry.controller.state < LifecycleStates.DESTROYED:
|
|
158
|
+
entry.controller.lifecycle_destroy()
|
|
159
|
+
|
|
160
|
+
for entry in self._entries_by_lifecycle.values():
|
|
161
|
+
rec(entry)
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import functools
|
|
2
|
+
|
|
3
|
+
from .. import check
|
|
4
|
+
from .. import dataclasses as dc
|
|
5
|
+
from .. import lang
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class LifecycleStateError(Exception):
|
|
9
|
+
pass
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@dc.dataclass(frozen=True, eq=False)
|
|
13
|
+
@functools.total_ordering
|
|
14
|
+
class LifecycleState(lang.Final):
|
|
15
|
+
name: str
|
|
16
|
+
phase: int
|
|
17
|
+
is_failed: bool
|
|
18
|
+
|
|
19
|
+
def __lt__(self, other):
|
|
20
|
+
return self.phase < check.isinstance(other, LifecycleState).phase
|
|
21
|
+
|
|
22
|
+
def __le__(self, other):
|
|
23
|
+
return self.phase <= check.isinstance(other, LifecycleState).phase
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class LifecycleStates(lang.Namespace):
|
|
27
|
+
NEW = LifecycleState('NEW', 0, False)
|
|
28
|
+
|
|
29
|
+
CONSTRUCTING = LifecycleState('CONSTRUCTING', 1, False)
|
|
30
|
+
FAILED_CONSTRUCTING = LifecycleState('FAILED_CONSTRUCTING', 2, True)
|
|
31
|
+
CONSTRUCTED = LifecycleState('CONSTRUCTED', 3, False)
|
|
32
|
+
|
|
33
|
+
STARTING = LifecycleState('STARTING', 4, False)
|
|
34
|
+
FAILED_STARTING = LifecycleState('FAILED_STARTING', 5, True)
|
|
35
|
+
STARTED = LifecycleState('STARTED', 6, False)
|
|
36
|
+
|
|
37
|
+
STOPPING = LifecycleState('STOPPING', 7, False)
|
|
38
|
+
FAILED_STOPPING = LifecycleState('FAILED_STOPPING', 8, True)
|
|
39
|
+
STOPPED = LifecycleState('STOPPED', 9, False)
|
|
40
|
+
|
|
41
|
+
DESTROYING = LifecycleState('DESTROYING', 10, False)
|
|
42
|
+
FAILED_DESTROYING = LifecycleState('FAILED_DESTROYING', 11, True)
|
|
43
|
+
DESTROYED = LifecycleState('DESTROYED', 12, False)
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
from .. import check
|
|
2
|
+
from .. import dataclasses as dc
|
|
3
|
+
from .. import lang
|
|
4
|
+
from .states import LifecycleState
|
|
5
|
+
from .states import LifecycleStates
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
@dc.dataclass(frozen=True)
|
|
9
|
+
class LifecycleTransition(lang.Final):
|
|
10
|
+
old: frozenset[LifecycleState]
|
|
11
|
+
new_intermediate: LifecycleState
|
|
12
|
+
new_failed: LifecycleState
|
|
13
|
+
new_succeeded: LifecycleState
|
|
14
|
+
|
|
15
|
+
def __post_init__(self) -> None:
|
|
16
|
+
dc.maybe_post_init(super())
|
|
17
|
+
check.unique([*self.old, self.new_intermediate, self.new_succeeded, self.new_failed])
|
|
18
|
+
check.arg(all(self.new_intermediate > o for o in self.old))
|
|
19
|
+
check.arg(self.new_failed > self.new_intermediate)
|
|
20
|
+
check.arg(self.new_succeeded > self.new_failed)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class LifecycleTransitions(lang.Namespace):
|
|
24
|
+
CONSTRUCT = LifecycleTransition(
|
|
25
|
+
frozenset([LifecycleStates.NEW]),
|
|
26
|
+
LifecycleStates.CONSTRUCTING,
|
|
27
|
+
LifecycleStates.FAILED_CONSTRUCTING,
|
|
28
|
+
LifecycleStates.CONSTRUCTED,
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
START = LifecycleTransition(
|
|
32
|
+
frozenset([LifecycleStates.CONSTRUCTED]),
|
|
33
|
+
LifecycleStates.STARTING,
|
|
34
|
+
LifecycleStates.FAILED_STARTING,
|
|
35
|
+
LifecycleStates.STARTED,
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
STOP = LifecycleTransition(
|
|
39
|
+
frozenset([LifecycleStates.STARTED]),
|
|
40
|
+
LifecycleStates.STOPPING,
|
|
41
|
+
LifecycleStates.FAILED_STOPPING,
|
|
42
|
+
LifecycleStates.STOPPED,
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
DESTROY = LifecycleTransition(
|
|
46
|
+
frozenset([
|
|
47
|
+
LifecycleStates.NEW,
|
|
48
|
+
|
|
49
|
+
LifecycleStates.CONSTRUCTING,
|
|
50
|
+
LifecycleStates.FAILED_CONSTRUCTING,
|
|
51
|
+
LifecycleStates.CONSTRUCTED,
|
|
52
|
+
|
|
53
|
+
LifecycleStates.STARTING,
|
|
54
|
+
LifecycleStates.FAILED_STARTING,
|
|
55
|
+
LifecycleStates.STARTED,
|
|
56
|
+
|
|
57
|
+
LifecycleStates.STOPPING,
|
|
58
|
+
LifecycleStates.FAILED_STOPPING,
|
|
59
|
+
LifecycleStates.STOPPED,
|
|
60
|
+
]),
|
|
61
|
+
LifecycleStates.DESTROYING,
|
|
62
|
+
LifecycleStates.FAILED_DESTROYING,
|
|
63
|
+
LifecycleStates.DESTROYED,
|
|
64
|
+
)
|
omlish/lite/__init__.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# @omlish-lite
|
omlish/lite/cached.py
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import functools
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class cached_nullary: # noqa
|
|
5
|
+
def __init__(self, fn):
|
|
6
|
+
super().__init__()
|
|
7
|
+
self._fn = fn
|
|
8
|
+
self._value = self._missing = object()
|
|
9
|
+
functools.update_wrapper(self, fn)
|
|
10
|
+
|
|
11
|
+
def __call__(self, *args, **kwargs): # noqa
|
|
12
|
+
if self._value is self._missing:
|
|
13
|
+
self._value = self._fn()
|
|
14
|
+
return self._value
|
|
15
|
+
|
|
16
|
+
def __get__(self, instance, owner): # noqa
|
|
17
|
+
bound = instance.__dict__[self._fn.__name__] = self.__class__(self._fn.__get__(instance, owner))
|
|
18
|
+
return bound
|
omlish/lite/check.py
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# ruff: noqa: UP006 UP007
|
|
2
|
+
import typing as ta
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
T = ta.TypeVar('T')
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def check_isinstance(v: T, spec: ta.Union[ta.Type[T], tuple]) -> T:
|
|
9
|
+
if not isinstance(v, spec):
|
|
10
|
+
raise TypeError(v)
|
|
11
|
+
return v
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def check_not_isinstance(v: T, spec: ta.Union[type, tuple]) -> T:
|
|
15
|
+
if isinstance(v, spec):
|
|
16
|
+
raise TypeError(v)
|
|
17
|
+
return v
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def check_not_none(v: ta.Optional[T]) -> T:
|
|
21
|
+
if v is None:
|
|
22
|
+
raise ValueError
|
|
23
|
+
return v
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def check_not(v: ta.Any) -> None:
|
|
27
|
+
if v:
|
|
28
|
+
raise ValueError(v)
|
|
29
|
+
return v
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import contextlib
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
@contextlib.contextmanager
|
|
5
|
+
def attr_setting(obj, attr, val, *, default=None): # noqa
|
|
6
|
+
not_set = object()
|
|
7
|
+
orig = getattr(obj, attr, not_set)
|
|
8
|
+
try:
|
|
9
|
+
setattr(obj, attr, val)
|
|
10
|
+
if orig is not not_set:
|
|
11
|
+
yield orig
|
|
12
|
+
else:
|
|
13
|
+
yield default
|
|
14
|
+
finally:
|
|
15
|
+
if orig is not_set:
|
|
16
|
+
delattr(obj, attr)
|
|
17
|
+
else:
|
|
18
|
+
setattr(obj, attr, orig)
|
omlish/lite/json.py
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import functools
|
|
2
|
+
import json
|
|
3
|
+
import typing as ta
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
##
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
JSON_PRETTY_INDENT = 2
|
|
10
|
+
|
|
11
|
+
JSON_PRETTY_KWARGS: ta.Mapping[str, ta.Any] = dict(
|
|
12
|
+
indent=JSON_PRETTY_INDENT,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
json_dump_pretty: ta.Callable[..., bytes] = functools.partial(json.dump, **JSON_PRETTY_KWARGS) # type: ignore
|
|
16
|
+
json_dumps_pretty: ta.Callable[..., str] = functools.partial(json.dumps, **JSON_PRETTY_KWARGS)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
##
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
JSON_COMPACT_SEPARATORS = (',', ':')
|
|
23
|
+
|
|
24
|
+
JSON_COMPACT_KWARGS: ta.Mapping[str, ta.Any] = dict(
|
|
25
|
+
indent=None,
|
|
26
|
+
separators=JSON_COMPACT_SEPARATORS,
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
json_dump_compact: ta.Callable[..., bytes] = functools.partial(json.dump, **JSON_COMPACT_KWARGS) # type: ignore
|
|
30
|
+
json_dumps_compact: ta.Callable[..., str] = functools.partial(json.dumps, **JSON_COMPACT_KWARGS)
|
omlish/lite/logs.py
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"""
|
|
2
|
+
TODO:
|
|
3
|
+
- debug
|
|
4
|
+
"""
|
|
5
|
+
# ruff: noqa: UP007
|
|
6
|
+
import logging
|
|
7
|
+
import typing as ta
|
|
8
|
+
|
|
9
|
+
from .json import json_dumps_compact
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
log = logging.getLogger(__name__)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class JsonLogFormatter(logging.Formatter):
|
|
16
|
+
|
|
17
|
+
KEYS: ta.Mapping[str, bool] = {
|
|
18
|
+
'name': False,
|
|
19
|
+
'msg': False,
|
|
20
|
+
'args': False,
|
|
21
|
+
'levelname': False,
|
|
22
|
+
'levelno': False,
|
|
23
|
+
'pathname': False,
|
|
24
|
+
'filename': False,
|
|
25
|
+
'module': False,
|
|
26
|
+
'exc_info': True,
|
|
27
|
+
'exc_text': True,
|
|
28
|
+
'stack_info': True,
|
|
29
|
+
'lineno': False,
|
|
30
|
+
'funcName': False,
|
|
31
|
+
'created': False,
|
|
32
|
+
'msecs': False,
|
|
33
|
+
'relativeCreated': False,
|
|
34
|
+
'thread': False,
|
|
35
|
+
'threadName': False,
|
|
36
|
+
'processName': False,
|
|
37
|
+
'process': False,
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
def format(self, record: logging.LogRecord) -> str:
|
|
41
|
+
dct = {
|
|
42
|
+
k: v
|
|
43
|
+
for k, o in self.KEYS.items()
|
|
44
|
+
for v in [getattr(record, k)]
|
|
45
|
+
if not (o and v is None)
|
|
46
|
+
}
|
|
47
|
+
return json_dumps_compact(dct)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def configure_standard_logging(level: ta.Union[int, str] = logging.INFO) -> None:
|
|
51
|
+
logging.root.addHandler(logging.StreamHandler())
|
|
52
|
+
logging.root.setLevel(level)
|