omlish 0.0.0.dev447__py3-none-any.whl → 0.0.0.dev493__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/.omlish-manifests.json +12 -0
- omlish/README.md +199 -0
- omlish/__about__.py +21 -16
- omlish/argparse/all.py +17 -9
- omlish/argparse/cli.py +16 -3
- omlish/argparse/utils.py +21 -0
- omlish/asyncs/asyncio/rlock.py +110 -0
- omlish/asyncs/asyncio/sync.py +43 -0
- omlish/asyncs/asyncio/utils.py +2 -0
- omlish/asyncs/sync.py +25 -0
- omlish/bootstrap/_marshal.py +1 -1
- omlish/bootstrap/diag.py +12 -21
- omlish/bootstrap/main.py +2 -5
- omlish/bootstrap/sys.py +27 -28
- omlish/cexts/__init__.py +0 -0
- omlish/cexts/include/omlish/omlish.hh +1 -0
- omlish/collections/__init__.py +13 -1
- omlish/collections/attrregistry.py +210 -0
- omlish/collections/cache/impl.py +1 -0
- omlish/collections/identity.py +1 -0
- omlish/collections/mappings.py +28 -0
- omlish/collections/trie.py +5 -1
- omlish/collections/utils.py +77 -0
- omlish/concurrent/all.py +2 -1
- omlish/concurrent/futures.py +25 -0
- omlish/concurrent/threadlets.py +1 -1
- omlish/daemons/reparent.py +2 -3
- omlish/daemons/spawning.py +2 -3
- omlish/dataclasses/__init__.py +2 -0
- omlish/dataclasses/impl/api/classes/decorator.py +3 -0
- omlish/dataclasses/impl/api/classes/make.py +3 -0
- omlish/dataclasses/impl/concerns/repr.py +15 -2
- omlish/dataclasses/impl/configs.py +97 -37
- omlish/dataclasses/impl/generation/compilation.py +21 -19
- omlish/dataclasses/impl/generation/globals.py +1 -0
- omlish/dataclasses/impl/generation/ops.py +1 -0
- omlish/dataclasses/impl/generation/plans.py +2 -17
- omlish/dataclasses/impl/generation/processor.py +106 -25
- omlish/dataclasses/impl/processing/base.py +8 -0
- omlish/dataclasses/impl/processing/driving.py +19 -7
- omlish/dataclasses/specs.py +1 -0
- omlish/dataclasses/tools/modifiers.py +5 -0
- omlish/diag/_pycharm/runhack.py +1 -1
- omlish/diag/cmds/__init__.py +0 -0
- omlish/diag/{lslocks.py → cmds/lslocks.py} +6 -6
- omlish/diag/{lsof.py → cmds/lsof.py} +6 -6
- omlish/diag/{ps.py → cmds/ps.py} +6 -6
- omlish/diag/pycharm.py +16 -2
- omlish/diag/pydevd.py +58 -40
- omlish/diag/replserver/console.py +1 -1
- omlish/dispatch/__init__.py +18 -12
- omlish/dispatch/methods.py +50 -140
- omlish/dom/rendering.py +1 -1
- omlish/formats/dotenv.py +1 -1
- omlish/formats/json/stream/__init__.py +13 -0
- omlish/funcs/guard.py +225 -0
- omlish/graphs/dot/rendering.py +1 -1
- omlish/http/all.py +44 -4
- omlish/http/clients/asyncs.py +33 -27
- omlish/http/clients/base.py +17 -1
- omlish/http/clients/coro/__init__.py +0 -0
- omlish/http/clients/coro/sync.py +171 -0
- omlish/http/clients/default.py +208 -29
- omlish/http/clients/executor.py +56 -0
- omlish/http/clients/httpx.py +72 -11
- omlish/http/clients/middleware.py +181 -0
- omlish/http/clients/sync.py +33 -27
- omlish/http/clients/syncasync.py +49 -0
- omlish/http/clients/urllib.py +6 -3
- omlish/http/coro/client/connection.py +15 -6
- omlish/http/coro/io.py +2 -0
- omlish/http/flasky/__init__.py +40 -0
- omlish/http/flasky/_compat.py +2 -0
- omlish/http/flasky/api.py +82 -0
- omlish/http/flasky/app.py +203 -0
- omlish/http/flasky/cvs.py +59 -0
- omlish/http/flasky/requests.py +20 -0
- omlish/http/flasky/responses.py +23 -0
- omlish/http/flasky/routes.py +23 -0
- omlish/http/flasky/types.py +15 -0
- omlish/http/urls.py +67 -0
- omlish/inject/__init__.py +57 -29
- omlish/inject/_dataclasses.py +5148 -0
- omlish/inject/binder.py +11 -52
- omlish/inject/eagers.py +2 -0
- omlish/inject/elements.py +27 -0
- omlish/inject/helpers/__init__.py +0 -0
- omlish/inject/{utils.py → helpers/constfn.py} +3 -3
- omlish/inject/{tags.py → helpers/id.py} +2 -2
- omlish/inject/helpers/late.py +76 -0
- omlish/inject/{managed.py → helpers/managed.py} +10 -10
- omlish/inject/helpers/multis.py +143 -0
- omlish/inject/helpers/wrappers.py +54 -0
- omlish/inject/impl/elements.py +54 -21
- omlish/inject/impl/injector.py +29 -25
- omlish/inject/impl/inspect.py +10 -1
- omlish/inject/impl/maysync.py +3 -4
- omlish/inject/impl/multis.py +3 -0
- omlish/inject/impl/sync.py +3 -4
- omlish/inject/injector.py +31 -2
- omlish/inject/inspect.py +35 -0
- omlish/inject/maysync.py +2 -4
- omlish/inject/multis.py +8 -0
- omlish/inject/overrides.py +3 -3
- omlish/inject/privates.py +6 -0
- omlish/inject/providers.py +3 -2
- omlish/inject/sync.py +5 -4
- omlish/io/buffers.py +118 -0
- omlish/io/readers.py +29 -0
- omlish/iterators/transforms.py +2 -2
- omlish/lang/__init__.py +180 -97
- omlish/lang/_asyncs.cc +186 -0
- omlish/lang/asyncs.py +17 -0
- omlish/lang/casing.py +11 -0
- omlish/lang/contextmanagers.py +28 -4
- omlish/lang/functions.py +31 -22
- omlish/lang/imports/_capture.cc +11 -9
- omlish/lang/imports/capture.py +363 -170
- omlish/lang/imports/proxy.py +455 -152
- omlish/lang/lazyglobals.py +22 -9
- omlish/lang/params.py +17 -0
- omlish/lang/recursion.py +0 -1
- omlish/lang/sequences.py +124 -0
- omlish/lifecycles/README.md +30 -0
- omlish/lifecycles/__init__.py +87 -13
- omlish/lifecycles/_dataclasses.py +1388 -0
- omlish/lifecycles/base.py +178 -64
- omlish/lifecycles/contextmanagers.py +113 -4
- omlish/lifecycles/controller.py +150 -87
- omlish/lifecycles/injection.py +143 -0
- omlish/lifecycles/listeners.py +56 -0
- omlish/lifecycles/managed.py +142 -0
- omlish/lifecycles/manager.py +218 -93
- omlish/lifecycles/states.py +2 -0
- omlish/lifecycles/transitions.py +3 -0
- omlish/lifecycles/unwrap.py +57 -0
- omlish/lite/abstract.py +54 -24
- omlish/lite/asyncs.py +2 -2
- omlish/lite/attrops.py +2 -0
- omlish/lite/contextmanagers.py +4 -4
- omlish/lite/dataclasses.py +44 -0
- omlish/lite/maybes.py +8 -0
- omlish/lite/maysync.py +1 -5
- omlish/lite/pycharm.py +1 -1
- omlish/lite/typing.py +24 -0
- omlish/logs/_amalg.py +1 -1
- omlish/logs/all.py +25 -11
- omlish/logs/asyncs.py +73 -0
- omlish/logs/base.py +101 -12
- omlish/logs/contexts.py +4 -1
- omlish/logs/lists.py +125 -0
- omlish/logs/modules.py +19 -1
- omlish/logs/std/loggers.py +6 -1
- omlish/logs/std/noisy.py +11 -9
- omlish/logs/{standard.py → std/standard.py} +3 -4
- omlish/logs/utils.py +17 -2
- omlish/manifests/loading.py +2 -1
- omlish/marshal/__init__.py +33 -13
- omlish/marshal/_dataclasses.py +2774 -0
- omlish/marshal/base/configs.py +12 -0
- omlish/marshal/base/contexts.py +36 -21
- omlish/marshal/base/funcs.py +8 -11
- omlish/marshal/base/options.py +8 -0
- omlish/marshal/base/registries.py +146 -44
- omlish/marshal/base/types.py +40 -16
- omlish/marshal/composite/iterables.py +33 -20
- omlish/marshal/composite/literals.py +20 -18
- omlish/marshal/composite/mappings.py +36 -23
- omlish/marshal/composite/maybes.py +29 -19
- omlish/marshal/composite/newtypes.py +16 -16
- omlish/marshal/composite/optionals.py +14 -14
- omlish/marshal/composite/special.py +15 -15
- omlish/marshal/composite/unions/__init__.py +0 -0
- omlish/marshal/composite/unions/literals.py +93 -0
- omlish/marshal/composite/unions/primitives.py +103 -0
- omlish/marshal/factories/invalidate.py +18 -68
- omlish/marshal/factories/method.py +26 -0
- omlish/marshal/factories/moduleimport/factories.py +22 -65
- omlish/marshal/factories/multi.py +13 -25
- omlish/marshal/factories/recursive.py +42 -56
- omlish/marshal/factories/typecache.py +29 -74
- omlish/marshal/factories/typemap.py +42 -43
- omlish/marshal/objects/dataclasses.py +129 -106
- omlish/marshal/objects/marshal.py +18 -14
- omlish/marshal/objects/namedtuples.py +48 -42
- omlish/marshal/objects/unmarshal.py +19 -15
- omlish/marshal/polymorphism/marshal.py +9 -11
- omlish/marshal/polymorphism/metadata.py +16 -5
- omlish/marshal/polymorphism/standard.py +13 -1
- omlish/marshal/polymorphism/unions.py +15 -105
- omlish/marshal/polymorphism/unmarshal.py +9 -10
- omlish/marshal/singular/enums.py +14 -18
- omlish/marshal/standard.py +10 -6
- omlish/marshal/trivial/any.py +1 -1
- omlish/marshal/trivial/forbidden.py +21 -26
- omlish/metadata.py +23 -1
- omlish/os/forkhooks.py +4 -0
- omlish/os/pidfiles/pinning.py +2 -2
- omlish/reflect/__init__.py +43 -26
- omlish/reflect/ops.py +10 -1
- omlish/reflect/types.py +1 -0
- omlish/secrets/marshal.py +1 -1
- omlish/specs/jmespath/__init__.py +12 -3
- omlish/specs/jmespath/_dataclasses.py +2893 -0
- omlish/specs/jmespath/ast.py +1 -1
- omlish/specs/jsonrpc/__init__.py +13 -0
- omlish/specs/jsonrpc/_marshal.py +32 -23
- omlish/specs/jsonrpc/conns.py +10 -7
- omlish/specs/jsonschema/_marshal.py +1 -1
- omlish/specs/jsonschema/keywords/__init__.py +7 -0
- omlish/specs/jsonschema/keywords/_dataclasses.py +1644 -0
- omlish/specs/openapi/_marshal.py +31 -22
- omlish/sql/__init__.py +24 -5
- omlish/sql/{tabledefs/alchemy.py → alchemy/tabledefs.py} +2 -2
- omlish/sql/api/dbapi.py +1 -1
- omlish/sql/dbapi/__init__.py +15 -0
- omlish/sql/{dbapi.py → dbapi/drivers.py} +2 -2
- omlish/sql/queries/__init__.py +3 -0
- omlish/sql/queries/_marshal.py +2 -2
- omlish/sql/queries/rendering.py +1 -1
- omlish/sql/tabledefs/_marshal.py +1 -1
- omlish/subprocesses/base.py +4 -0
- omlish/subprocesses/editor.py +1 -1
- omlish/sync.py +155 -21
- omlish/term/alt.py +60 -0
- omlish/term/confirm.py +8 -8
- omlish/term/pager.py +235 -0
- omlish/term/terminfo.py +935 -0
- omlish/term/termstate.py +67 -0
- omlish/term/vt100/terminal.py +0 -3
- omlish/testing/pytest/plugins/asyncs/fixtures.py +4 -1
- omlish/testing/pytest/plugins/asyncs/plugin.py +2 -0
- omlish/testing/pytest/plugins/skips.py +2 -1
- omlish/testing/unittest/main.py +3 -3
- omlish/text/docwrap/__init__.py +3 -0
- omlish/text/docwrap/__main__.py +11 -0
- omlish/text/docwrap/api.py +83 -0
- omlish/text/docwrap/cli.py +91 -0
- omlish/text/docwrap/groups.py +84 -0
- omlish/text/docwrap/lists.py +167 -0
- omlish/text/docwrap/parts.py +146 -0
- omlish/text/docwrap/reflowing.py +106 -0
- omlish/text/docwrap/rendering.py +151 -0
- omlish/text/docwrap/utils.py +11 -0
- omlish/text/docwrap/wrapping.py +59 -0
- omlish/text/filecache.py +2 -2
- omlish/text/lorem.py +6 -0
- omlish/text/parts.py +2 -2
- omlish/text/textwrap.py +51 -0
- omlish/typedvalues/marshal.py +85 -59
- omlish/typedvalues/values.py +2 -1
- {omlish-0.0.0.dev447.dist-info → omlish-0.0.0.dev493.dist-info}/METADATA +36 -32
- {omlish-0.0.0.dev447.dist-info → omlish-0.0.0.dev493.dist-info}/RECORD +260 -199
- omlish/dataclasses/impl/generation/mangling.py +0 -18
- omlish/funcs/match.py +0 -227
- omlish/lifecycles/abstract.py +0 -86
- omlish/marshal/factories/match.py +0 -34
- omlish/marshal/factories/simple.py +0 -28
- /omlish/inject/{impl → helpers}/proxy.py +0 -0
- /omlish/inject/impl/{providers2.py → providersmap.py} +0 -0
- /omlish/sql/{abc.py → dbapi/abc.py} +0 -0
- {omlish-0.0.0.dev447.dist-info → omlish-0.0.0.dev493.dist-info}/WHEEL +0 -0
- {omlish-0.0.0.dev447.dist-info → omlish-0.0.0.dev493.dist-info}/entry_points.txt +0 -0
- {omlish-0.0.0.dev447.dist-info → omlish-0.0.0.dev493.dist-info}/licenses/LICENSE +0 -0
- {omlish-0.0.0.dev447.dist-info → omlish-0.0.0.dev493.dist-info}/top_level.txt +0 -0
omlish/lite/dataclasses.py
CHANGED
|
@@ -100,6 +100,36 @@ def dataclass_repr_omit_falsey(obj: ta.Any) -> str:
|
|
|
100
100
|
##
|
|
101
101
|
|
|
102
102
|
|
|
103
|
+
def dataclass_descriptor_method(*bind_attrs: str, bind_owner: bool = False) -> ta.Callable:
|
|
104
|
+
if not bind_attrs:
|
|
105
|
+
def __get__(self, instance, owner=None): # noqa
|
|
106
|
+
return self
|
|
107
|
+
|
|
108
|
+
elif bind_owner:
|
|
109
|
+
def __get__(self, instance, owner=None): # noqa
|
|
110
|
+
# Guaranteed to return a new instance even with no attrs
|
|
111
|
+
return dc.replace(self, **{
|
|
112
|
+
a: v.__get__(instance, owner) if (v := getattr(self, a)) is not None else None
|
|
113
|
+
for a in bind_attrs
|
|
114
|
+
})
|
|
115
|
+
|
|
116
|
+
else:
|
|
117
|
+
def __get__(self, instance, owner=None): # noqa
|
|
118
|
+
if instance is None:
|
|
119
|
+
return self
|
|
120
|
+
|
|
121
|
+
# Guaranteed to return a new instance even with no attrs
|
|
122
|
+
return dc.replace(self, **{
|
|
123
|
+
a: v.__get__(instance, owner) if (v := getattr(self, a)) is not None else None
|
|
124
|
+
for a in bind_attrs
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
return __get__
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
##
|
|
131
|
+
|
|
132
|
+
|
|
103
133
|
def dataclass_kw_only_init():
|
|
104
134
|
def inner(cls):
|
|
105
135
|
if not isinstance(cls, type) and dc.is_dataclass(cls):
|
|
@@ -161,3 +191,17 @@ def dataclass_kw_only_init():
|
|
|
161
191
|
return cls
|
|
162
192
|
|
|
163
193
|
return inner
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
##
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
@dc.dataclass()
|
|
200
|
+
class DataclassFieldRequiredError(Exception):
|
|
201
|
+
name: str
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
def dataclass_field_required(name: str) -> ta.Callable[[], ta.Any]:
|
|
205
|
+
def inner() -> ta.NoReturn:
|
|
206
|
+
raise DataclassFieldRequiredError(name)
|
|
207
|
+
return inner
|
omlish/lite/maybes.py
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# ruff: noqa: UP007 UP045
|
|
2
2
|
import abc
|
|
3
3
|
import functools
|
|
4
|
+
import operator
|
|
4
5
|
import typing as ta
|
|
5
6
|
|
|
6
7
|
from .abstract import Abstract
|
|
@@ -208,3 +209,10 @@ class _EmptyMaybe(_Maybe[T]):
|
|
|
208
209
|
|
|
209
210
|
|
|
210
211
|
Maybe._empty = _EmptyMaybe() # noqa
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
##
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
setattr(Maybe, 'just', _JustMaybe) # noqa
|
|
218
|
+
setattr(Maybe, 'empty', functools.partial(operator.attrgetter('_empty'), Maybe))
|
omlish/lite/maysync.py
CHANGED
|
@@ -25,6 +25,7 @@ Internally, it's not really correct to say that there is 'no event loop' in the
|
|
|
25
25
|
===
|
|
26
26
|
|
|
27
27
|
TODO:
|
|
28
|
+
- ! impl iterators not just generators !
|
|
28
29
|
- __del__
|
|
29
30
|
- (test) maysync context managers
|
|
30
31
|
- CancelledError
|
|
@@ -33,11 +34,6 @@ TODO:
|
|
|
33
34
|
- works down to 3.8
|
|
34
35
|
- make_maysync_from_sync can run with asyncio.run_in_thread
|
|
35
36
|
- make_maysync_from_async can run with asyncio.run_soon
|
|
36
|
-
|
|
37
|
-
TODO OVERHAUL:
|
|
38
|
-
- no more sync/async context, just one Context, and it means sync
|
|
39
|
-
- make FpMaywaitable *not reusable*
|
|
40
|
-
- `cannot reuse already awaited coroutine`
|
|
41
37
|
"""
|
|
42
38
|
import abc
|
|
43
39
|
import inspect
|
omlish/lite/pycharm.py
CHANGED
omlish/lite/typing.py
CHANGED
|
@@ -12,6 +12,12 @@ A2 = ta.TypeVar('A2')
|
|
|
12
12
|
|
|
13
13
|
##
|
|
14
14
|
# A workaround for typing deficiencies (like `Argument 2 to NewType(...) must be subclassable`).
|
|
15
|
+
#
|
|
16
|
+
# Note that this problem doesn't happen at runtime - it happens in mypy:
|
|
17
|
+
#
|
|
18
|
+
# mypy <(echo "import typing as ta; MyCallback = ta.NewType('MyCallback', ta.Callable[[], None])")
|
|
19
|
+
# /dev/fd/11:1:22: error: Argument 2 to NewType(...) must be subclassable (got "Callable[[], None]") [valid-newtype]
|
|
20
|
+
#
|
|
15
21
|
|
|
16
22
|
|
|
17
23
|
@dc.dataclass(frozen=True)
|
|
@@ -57,6 +63,24 @@ class Func3(ta.Generic[A0, A1, A2, T]):
|
|
|
57
63
|
##
|
|
58
64
|
|
|
59
65
|
|
|
66
|
+
@dc.dataclass(frozen=True)
|
|
67
|
+
class CachedFunc0(ta.Generic[T]):
|
|
68
|
+
fn: ta.Callable[[], T]
|
|
69
|
+
|
|
70
|
+
def __call__(self) -> T:
|
|
71
|
+
try:
|
|
72
|
+
return object.__getattribute__(self, '_value')
|
|
73
|
+
except AttributeError:
|
|
74
|
+
pass
|
|
75
|
+
|
|
76
|
+
value = self.fn()
|
|
77
|
+
object.__setattr__(self, '_value', value)
|
|
78
|
+
return value
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
##
|
|
82
|
+
|
|
83
|
+
|
|
60
84
|
_TYPING_ANNOTATIONS_ATTR = '__annotate__' if sys.version_info >= (3, 14) else '__annotations__'
|
|
61
85
|
|
|
62
86
|
|
omlish/logs/_amalg.py
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# @omlish-lite
|
|
2
2
|
# @omlish-amalg ../../omdev/scripts/lib/logs.py
|
|
3
3
|
from .base import AnyLogger # noqa
|
|
4
|
-
from .standard import configure_standard_logging # noqa
|
|
5
4
|
from .std.loggers import StdLogger # noqa
|
|
5
|
+
from .std.standard import configure_standard_logging # noqa
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
##
|
omlish/logs/all.py
CHANGED
|
@@ -38,6 +38,20 @@ with _lang.auto_proxy_init(globals()):
|
|
|
38
38
|
LoggingContextLogRecord,
|
|
39
39
|
)
|
|
40
40
|
|
|
41
|
+
from .std.standard import ( # noqa
|
|
42
|
+
STANDARD_LOG_FORMAT_PARTS,
|
|
43
|
+
StandardLoggingFormatter,
|
|
44
|
+
|
|
45
|
+
StandardConfiguredLoggingHandler,
|
|
46
|
+
|
|
47
|
+
configure_standard_logging,
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
from .asyncs import ( # noqa
|
|
51
|
+
AsyncLoggerToLogger,
|
|
52
|
+
LoggerToAsyncLogger,
|
|
53
|
+
)
|
|
54
|
+
|
|
41
55
|
from .base import ( # noqa
|
|
42
56
|
AnyLogger,
|
|
43
57
|
Logger,
|
|
@@ -67,28 +81,28 @@ with _lang.auto_proxy_init(globals()):
|
|
|
67
81
|
NamedLogLevel,
|
|
68
82
|
)
|
|
69
83
|
|
|
84
|
+
from .lists import ( # noqa
|
|
85
|
+
AnyListLogger,
|
|
86
|
+
ListLogger,
|
|
87
|
+
AsyncLogger,
|
|
88
|
+
)
|
|
89
|
+
|
|
70
90
|
from .modules import ( # noqa
|
|
71
91
|
get_module_logger,
|
|
92
|
+
get_module_async_logger,
|
|
93
|
+
get_module_loggers,
|
|
72
94
|
)
|
|
73
95
|
|
|
74
96
|
from .protocols import ( # noqa
|
|
75
97
|
LoggerLike,
|
|
76
98
|
)
|
|
77
99
|
|
|
78
|
-
from .standard import ( # noqa
|
|
79
|
-
STANDARD_LOG_FORMAT_PARTS,
|
|
80
|
-
StandardLoggingFormatter,
|
|
81
|
-
|
|
82
|
-
StandardConfiguredLoggingHandler,
|
|
83
|
-
|
|
84
|
-
configure_standard_logging,
|
|
85
|
-
)
|
|
86
|
-
|
|
87
100
|
from .utils import ( # noqa
|
|
101
|
+
exception_logging,
|
|
102
|
+
async_exception_logging,
|
|
103
|
+
|
|
88
104
|
LogTimingContext,
|
|
89
105
|
log_timing_context,
|
|
90
|
-
|
|
91
|
-
error_logging,
|
|
92
106
|
)
|
|
93
107
|
|
|
94
108
|
from .warnings import ( # noqa
|
omlish/logs/asyncs.py
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# ruff: noqa: UP006 UP007 UP045 UP046
|
|
2
|
+
# @omlish-lite
|
|
3
|
+
import typing as ta
|
|
4
|
+
|
|
5
|
+
from ..lite.asyncs import sync_await
|
|
6
|
+
from ..lite.check import check
|
|
7
|
+
from .base import AsyncLogger
|
|
8
|
+
from .base import CaptureLoggingContext
|
|
9
|
+
from .base import Logger
|
|
10
|
+
from .base import LoggingMsgFn
|
|
11
|
+
from .contexts import CaptureLoggingContextImpl
|
|
12
|
+
from .infos import LoggingContextInfos
|
|
13
|
+
from .levels import LogLevel
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
##
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class AsyncLoggerToLogger(Logger):
|
|
20
|
+
def __init__(self, u: AsyncLogger) -> None:
|
|
21
|
+
super().__init__()
|
|
22
|
+
|
|
23
|
+
self._u = u
|
|
24
|
+
|
|
25
|
+
def get_effective_level(self) -> LogLevel:
|
|
26
|
+
return self._u.get_effective_level()
|
|
27
|
+
|
|
28
|
+
def _log(
|
|
29
|
+
self,
|
|
30
|
+
ctx: CaptureLoggingContext,
|
|
31
|
+
msg: ta.Union[str, tuple, LoggingMsgFn],
|
|
32
|
+
*args: ta.Any,
|
|
33
|
+
**kwargs: ta.Any,
|
|
34
|
+
) -> None:
|
|
35
|
+
# Nope out early to avoid sync_await if possible - don't bother in the LoggerToAsyncLogger.
|
|
36
|
+
if not self.is_enabled_for(ctx.must_get_info(LoggingContextInfos.Level).level):
|
|
37
|
+
return
|
|
38
|
+
|
|
39
|
+
# Note: we hardcode the stack offset of sync_await (which is 2 - sync_await + sync_await.thunk). In non-lite
|
|
40
|
+
# code, lang.sync_await uses a cext if present to avoid being on the py stack, which would obviously complicate
|
|
41
|
+
# this, but this is lite code so we will always have the non-c version.
|
|
42
|
+
sync_await(
|
|
43
|
+
self._u._log( # noqa
|
|
44
|
+
check.isinstance(ctx, CaptureLoggingContextImpl).inc_stack_offset(3),
|
|
45
|
+
msg,
|
|
46
|
+
*args,
|
|
47
|
+
**kwargs,
|
|
48
|
+
),
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class LoggerToAsyncLogger(AsyncLogger):
|
|
53
|
+
def __init__(self, u: Logger) -> None:
|
|
54
|
+
super().__init__()
|
|
55
|
+
|
|
56
|
+
self._u = u
|
|
57
|
+
|
|
58
|
+
def get_effective_level(self) -> LogLevel:
|
|
59
|
+
return self._u.get_effective_level()
|
|
60
|
+
|
|
61
|
+
async def _log(
|
|
62
|
+
self,
|
|
63
|
+
ctx: CaptureLoggingContext,
|
|
64
|
+
msg: ta.Union[str, tuple, LoggingMsgFn],
|
|
65
|
+
*args: ta.Any,
|
|
66
|
+
**kwargs: ta.Any,
|
|
67
|
+
) -> None:
|
|
68
|
+
return self._u._log( # noqa
|
|
69
|
+
check.isinstance(ctx, CaptureLoggingContextImpl).inc_stack_offset(),
|
|
70
|
+
msg,
|
|
71
|
+
*args,
|
|
72
|
+
**kwargs,
|
|
73
|
+
)
|
omlish/logs/base.py
CHANGED
|
@@ -40,6 +40,11 @@ class AnyLogger(Abstract, ta.Generic[T]):
|
|
|
40
40
|
|
|
41
41
|
##
|
|
42
42
|
|
|
43
|
+
# This will be 1 for [Sync]Logger and 0 for AsyncLogger - in sync loggers these methods remain present on the stack,
|
|
44
|
+
# in async loggers they return a coroutine to be awaited and thus aren't actually present when said coroutine is
|
|
45
|
+
# awaited.
|
|
46
|
+
_level_proxy_method_stack_offset: ta.ClassVar[int]
|
|
47
|
+
|
|
43
48
|
@ta.overload
|
|
44
49
|
def log(self, level: LogLevel, msg: str, *args: ta.Any, **kwargs: ta.Any) -> T:
|
|
45
50
|
...
|
|
@@ -54,7 +59,14 @@ class AnyLogger(Abstract, ta.Generic[T]):
|
|
|
54
59
|
|
|
55
60
|
@ta.final
|
|
56
61
|
def log(self, level: LogLevel, *args, **kwargs):
|
|
57
|
-
return self._log(
|
|
62
|
+
return self._log(
|
|
63
|
+
CaptureLoggingContextImpl(
|
|
64
|
+
level,
|
|
65
|
+
stack_offset=self._level_proxy_method_stack_offset,
|
|
66
|
+
),
|
|
67
|
+
*args,
|
|
68
|
+
**kwargs,
|
|
69
|
+
)
|
|
58
70
|
|
|
59
71
|
#
|
|
60
72
|
|
|
@@ -72,7 +84,14 @@ class AnyLogger(Abstract, ta.Generic[T]):
|
|
|
72
84
|
|
|
73
85
|
@ta.final
|
|
74
86
|
def debug(self, *args, **kwargs):
|
|
75
|
-
return self._log(
|
|
87
|
+
return self._log(
|
|
88
|
+
CaptureLoggingContextImpl(
|
|
89
|
+
NamedLogLevel.DEBUG,
|
|
90
|
+
stack_offset=self._level_proxy_method_stack_offset,
|
|
91
|
+
),
|
|
92
|
+
*args,
|
|
93
|
+
**kwargs,
|
|
94
|
+
)
|
|
76
95
|
|
|
77
96
|
#
|
|
78
97
|
|
|
@@ -90,7 +109,14 @@ class AnyLogger(Abstract, ta.Generic[T]):
|
|
|
90
109
|
|
|
91
110
|
@ta.final
|
|
92
111
|
def info(self, *args, **kwargs):
|
|
93
|
-
return self._log(
|
|
112
|
+
return self._log(
|
|
113
|
+
CaptureLoggingContextImpl(
|
|
114
|
+
NamedLogLevel.INFO,
|
|
115
|
+
stack_offset=self._level_proxy_method_stack_offset,
|
|
116
|
+
),
|
|
117
|
+
*args,
|
|
118
|
+
**kwargs,
|
|
119
|
+
)
|
|
94
120
|
|
|
95
121
|
#
|
|
96
122
|
|
|
@@ -108,7 +134,14 @@ class AnyLogger(Abstract, ta.Generic[T]):
|
|
|
108
134
|
|
|
109
135
|
@ta.final
|
|
110
136
|
def warning(self, *args, **kwargs):
|
|
111
|
-
return self._log(
|
|
137
|
+
return self._log(
|
|
138
|
+
CaptureLoggingContextImpl(
|
|
139
|
+
NamedLogLevel.WARNING,
|
|
140
|
+
stack_offset=self._level_proxy_method_stack_offset,
|
|
141
|
+
),
|
|
142
|
+
*args,
|
|
143
|
+
**kwargs,
|
|
144
|
+
)
|
|
112
145
|
|
|
113
146
|
#
|
|
114
147
|
|
|
@@ -126,7 +159,14 @@ class AnyLogger(Abstract, ta.Generic[T]):
|
|
|
126
159
|
|
|
127
160
|
@ta.final
|
|
128
161
|
def error(self, *args, **kwargs):
|
|
129
|
-
return self._log(
|
|
162
|
+
return self._log(
|
|
163
|
+
CaptureLoggingContextImpl(
|
|
164
|
+
NamedLogLevel.ERROR,
|
|
165
|
+
stack_offset=self._level_proxy_method_stack_offset,
|
|
166
|
+
),
|
|
167
|
+
*args,
|
|
168
|
+
**kwargs,
|
|
169
|
+
)
|
|
130
170
|
|
|
131
171
|
#
|
|
132
172
|
|
|
@@ -144,7 +184,15 @@ class AnyLogger(Abstract, ta.Generic[T]):
|
|
|
144
184
|
|
|
145
185
|
@ta.final
|
|
146
186
|
def exception(self, *args, exc_info: LoggingExcInfoArg = True, **kwargs):
|
|
147
|
-
return self._log(
|
|
187
|
+
return self._log(
|
|
188
|
+
CaptureLoggingContextImpl(
|
|
189
|
+
NamedLogLevel.ERROR,
|
|
190
|
+
exc_info=exc_info,
|
|
191
|
+
stack_offset=self._level_proxy_method_stack_offset,
|
|
192
|
+
),
|
|
193
|
+
*args,
|
|
194
|
+
**kwargs,
|
|
195
|
+
)
|
|
148
196
|
|
|
149
197
|
#
|
|
150
198
|
|
|
@@ -162,24 +210,53 @@ class AnyLogger(Abstract, ta.Generic[T]):
|
|
|
162
210
|
|
|
163
211
|
@ta.final
|
|
164
212
|
def critical(self, *args, **kwargs):
|
|
165
|
-
return self._log(
|
|
213
|
+
return self._log(
|
|
214
|
+
CaptureLoggingContextImpl(
|
|
215
|
+
NamedLogLevel.CRITICAL,
|
|
216
|
+
stack_offset=self._level_proxy_method_stack_offset,
|
|
217
|
+
),
|
|
218
|
+
*args,
|
|
219
|
+
**kwargs,
|
|
220
|
+
)
|
|
166
221
|
|
|
167
222
|
##
|
|
168
223
|
|
|
169
224
|
@abc.abstractmethod
|
|
170
|
-
def _log(
|
|
225
|
+
def _log(
|
|
226
|
+
self,
|
|
227
|
+
ctx: CaptureLoggingContext,
|
|
228
|
+
msg: ta.Union[str, tuple, LoggingMsgFn],
|
|
229
|
+
*args: ta.Any,
|
|
230
|
+
**kwargs: ta.Any,
|
|
231
|
+
) -> T:
|
|
171
232
|
raise NotImplementedError
|
|
172
233
|
|
|
173
234
|
|
|
174
235
|
class Logger(AnyLogger[None], Abstract):
|
|
236
|
+
_level_proxy_method_stack_offset: ta.ClassVar[int] = 1
|
|
237
|
+
|
|
175
238
|
@abc.abstractmethod
|
|
176
|
-
def _log(
|
|
239
|
+
def _log(
|
|
240
|
+
self,
|
|
241
|
+
ctx: CaptureLoggingContext,
|
|
242
|
+
msg: ta.Union[str, tuple, LoggingMsgFn],
|
|
243
|
+
*args: ta.Any,
|
|
244
|
+
**kwargs: ta.Any,
|
|
245
|
+
) -> None:
|
|
177
246
|
raise NotImplementedError
|
|
178
247
|
|
|
179
248
|
|
|
180
249
|
class AsyncLogger(AnyLogger[ta.Awaitable[None]], Abstract):
|
|
250
|
+
_level_proxy_method_stack_offset: ta.ClassVar[int] = 0
|
|
251
|
+
|
|
181
252
|
@abc.abstractmethod
|
|
182
|
-
def _log(
|
|
253
|
+
def _log(
|
|
254
|
+
self,
|
|
255
|
+
ctx: CaptureLoggingContext,
|
|
256
|
+
msg: ta.Union[str, tuple, LoggingMsgFn],
|
|
257
|
+
*args: ta.Any,
|
|
258
|
+
**kwargs: ta.Any,
|
|
259
|
+
) -> ta.Awaitable[None]:
|
|
183
260
|
raise NotImplementedError
|
|
184
261
|
|
|
185
262
|
|
|
@@ -194,11 +271,23 @@ class AnyNopLogger(AnyLogger[T], Abstract):
|
|
|
194
271
|
|
|
195
272
|
@ta.final
|
|
196
273
|
class NopLogger(AnyNopLogger[None], Logger):
|
|
197
|
-
def _log(
|
|
274
|
+
def _log(
|
|
275
|
+
self,
|
|
276
|
+
ctx: CaptureLoggingContext,
|
|
277
|
+
msg: ta.Union[str, tuple, LoggingMsgFn],
|
|
278
|
+
*args: ta.Any,
|
|
279
|
+
**kwargs: ta.Any,
|
|
280
|
+
) -> None:
|
|
198
281
|
pass
|
|
199
282
|
|
|
200
283
|
|
|
201
284
|
@ta.final
|
|
202
285
|
class AsyncNopLogger(AnyNopLogger[ta.Awaitable[None]], AsyncLogger):
|
|
203
|
-
async def _log(
|
|
286
|
+
async def _log(
|
|
287
|
+
self,
|
|
288
|
+
ctx: CaptureLoggingContext,
|
|
289
|
+
msg: ta.Union[str, tuple, LoggingMsgFn],
|
|
290
|
+
*args: ta.Any,
|
|
291
|
+
**kwargs: ta.Any,
|
|
292
|
+
) -> None:
|
|
204
293
|
pass
|
omlish/logs/contexts.py
CHANGED
|
@@ -118,6 +118,9 @@ class CaptureLoggingContextImpl(CaptureLoggingContext):
|
|
|
118
118
|
self._infos[type(info)] = info
|
|
119
119
|
return self
|
|
120
120
|
|
|
121
|
+
def get_infos(self) -> ta.Mapping[ta.Type[LoggingContextInfo], LoggingContextInfo]:
|
|
122
|
+
return self._infos
|
|
123
|
+
|
|
121
124
|
def get_info(self, ty: ta.Type[LoggingContextInfoT]) -> ta.Optional[LoggingContextInfoT]:
|
|
122
125
|
return self._infos.get(ty)
|
|
123
126
|
|
|
@@ -140,7 +143,7 @@ class CaptureLoggingContextImpl(CaptureLoggingContext):
|
|
|
140
143
|
_stack_offset: int
|
|
141
144
|
_stack_info: bool
|
|
142
145
|
|
|
143
|
-
def inc_stack_offset(self, ofs: int = 1) -> '
|
|
146
|
+
def inc_stack_offset(self, ofs: int = 1) -> 'CaptureLoggingContextImpl':
|
|
144
147
|
if hasattr(self, '_stack_offset'):
|
|
145
148
|
self._stack_offset += ofs
|
|
146
149
|
return self
|
omlish/logs/lists.py
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# ruff: noqa: N802 UP006 UP007 UP045
|
|
2
|
+
# @omlish-lite
|
|
3
|
+
import dataclasses as dc
|
|
4
|
+
import typing as ta
|
|
5
|
+
|
|
6
|
+
from ..lite.abstract import Abstract
|
|
7
|
+
from ..lite.check import check
|
|
8
|
+
from .base import AnyLogger
|
|
9
|
+
from .base import AsyncLogger
|
|
10
|
+
from .base import CaptureLoggingContext
|
|
11
|
+
from .base import Logger
|
|
12
|
+
from .base import LoggingMsgFn
|
|
13
|
+
from .contexts import CaptureLoggingContextImpl
|
|
14
|
+
from .infos import LoggingContextInfo
|
|
15
|
+
from .infos import LoggingContextInfos
|
|
16
|
+
from .levels import LogLevel
|
|
17
|
+
from .levels import NamedLogLevel
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
T = ta.TypeVar('T')
|
|
21
|
+
|
|
22
|
+
LoggingContextInfoT = ta.TypeVar('LoggingContextInfoT', bound=LoggingContextInfo)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
##
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@dc.dataclass(frozen=True)
|
|
29
|
+
class ListLoggerEntry:
|
|
30
|
+
infos: ta.Mapping[ta.Type[LoggingContextInfo], LoggingContextInfo]
|
|
31
|
+
|
|
32
|
+
def get_info(self, ty: ta.Type[LoggingContextInfoT]) -> ta.Optional[LoggingContextInfoT]:
|
|
33
|
+
return self.infos.get(ty)
|
|
34
|
+
|
|
35
|
+
@ta.final
|
|
36
|
+
def __getitem__(self, ty: ta.Type[LoggingContextInfoT]) -> ta.Optional[LoggingContextInfoT]:
|
|
37
|
+
return self.get_info(ty)
|
|
38
|
+
|
|
39
|
+
def must_get_info(self, ty: ta.Type[LoggingContextInfoT]) -> LoggingContextInfoT:
|
|
40
|
+
return check.not_none(self.get_info(ty))
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class AnyListLogger(AnyLogger[T], Abstract):
|
|
44
|
+
def __init__(
|
|
45
|
+
self,
|
|
46
|
+
*,
|
|
47
|
+
name: ta.Optional[str] = None,
|
|
48
|
+
level: LogLevel = NamedLogLevel.NOTSET,
|
|
49
|
+
) -> None:
|
|
50
|
+
super().__init__()
|
|
51
|
+
|
|
52
|
+
if name is None:
|
|
53
|
+
name = f'{type(self).__name__}@{id(self):x}'
|
|
54
|
+
self._name = name
|
|
55
|
+
self._level = level
|
|
56
|
+
|
|
57
|
+
self._entries: ta.List[ListLoggerEntry] = []
|
|
58
|
+
|
|
59
|
+
@property
|
|
60
|
+
def name(self) -> str:
|
|
61
|
+
return self._name
|
|
62
|
+
|
|
63
|
+
@property
|
|
64
|
+
def entries(self) -> ta.List[ListLoggerEntry]:
|
|
65
|
+
"""Intentionally mutable."""
|
|
66
|
+
|
|
67
|
+
return self._entries
|
|
68
|
+
|
|
69
|
+
def set_level(self, level: LogLevel) -> None:
|
|
70
|
+
self._level = level
|
|
71
|
+
|
|
72
|
+
def get_effective_level(self) -> LogLevel:
|
|
73
|
+
return self._level
|
|
74
|
+
|
|
75
|
+
def _add_entry(
|
|
76
|
+
self,
|
|
77
|
+
ctx: CaptureLoggingContextImpl,
|
|
78
|
+
msg: ta.Union[str, tuple, LoggingMsgFn],
|
|
79
|
+
*args: ta.Any,
|
|
80
|
+
) -> None:
|
|
81
|
+
if not self.is_enabled_for(ctx.must_get_info(LoggingContextInfos.Level).level):
|
|
82
|
+
return
|
|
83
|
+
|
|
84
|
+
ctx.set_basic(
|
|
85
|
+
name=self._name,
|
|
86
|
+
|
|
87
|
+
msg=msg,
|
|
88
|
+
args=args,
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
ctx.capture()
|
|
92
|
+
|
|
93
|
+
self._entries.append(ListLoggerEntry(ctx.get_infos()))
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
class ListLogger(AnyListLogger[None], Logger):
|
|
97
|
+
def _log(
|
|
98
|
+
self,
|
|
99
|
+
ctx: CaptureLoggingContext,
|
|
100
|
+
msg: ta.Union[str, tuple, LoggingMsgFn],
|
|
101
|
+
*args: ta.Any,
|
|
102
|
+
**kwargs: ta.Any,
|
|
103
|
+
) -> None:
|
|
104
|
+
self._add_entry(
|
|
105
|
+
check.isinstance(ctx, CaptureLoggingContextImpl).inc_stack_offset(),
|
|
106
|
+
msg,
|
|
107
|
+
*args,
|
|
108
|
+
**kwargs,
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
class ListAsyncLogger(AnyListLogger[ta.Awaitable[None]], AsyncLogger):
|
|
113
|
+
async def _log(
|
|
114
|
+
self,
|
|
115
|
+
ctx: CaptureLoggingContext,
|
|
116
|
+
msg: ta.Union[str, tuple, LoggingMsgFn],
|
|
117
|
+
*args: ta.Any,
|
|
118
|
+
**kwargs: ta.Any,
|
|
119
|
+
) -> None:
|
|
120
|
+
self._add_entry(
|
|
121
|
+
check.isinstance(ctx, CaptureLoggingContextImpl).inc_stack_offset(),
|
|
122
|
+
msg,
|
|
123
|
+
*args,
|
|
124
|
+
**kwargs,
|
|
125
|
+
)
|
omlish/logs/modules.py
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
|
+
# ruff: noqa: UP006
|
|
1
2
|
# @omlish-lite
|
|
2
3
|
import logging
|
|
3
4
|
import typing as ta
|
|
4
5
|
|
|
6
|
+
from .asyncs import LoggerToAsyncLogger
|
|
7
|
+
from .base import AsyncLogger
|
|
5
8
|
from .base import Logger
|
|
6
9
|
from .std.loggers import StdLogger
|
|
7
10
|
|
|
@@ -9,5 +12,20 @@ from .std.loggers import StdLogger
|
|
|
9
12
|
##
|
|
10
13
|
|
|
11
14
|
|
|
15
|
+
def _get_module_std_logger(mod_globals: ta.Mapping[str, ta.Any]) -> logging.Logger:
|
|
16
|
+
return logging.getLogger(mod_globals.get('__name__'))
|
|
17
|
+
|
|
18
|
+
|
|
12
19
|
def get_module_logger(mod_globals: ta.Mapping[str, ta.Any]) -> Logger:
|
|
13
|
-
return StdLogger(
|
|
20
|
+
return StdLogger(_get_module_std_logger(mod_globals))
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def get_module_async_logger(mod_globals: ta.Mapping[str, ta.Any]) -> AsyncLogger:
|
|
24
|
+
return LoggerToAsyncLogger(get_module_logger(mod_globals))
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def get_module_loggers(mod_globals: ta.Mapping[str, ta.Any]) -> ta.Tuple[Logger, AsyncLogger]:
|
|
28
|
+
return (
|
|
29
|
+
log := get_module_logger(mod_globals),
|
|
30
|
+
LoggerToAsyncLogger(log),
|
|
31
|
+
)
|
omlish/logs/std/loggers.py
CHANGED
|
@@ -30,7 +30,12 @@ class StdLogger(Logger):
|
|
|
30
30
|
def get_effective_level(self) -> LogLevel:
|
|
31
31
|
return self._std.getEffectiveLevel()
|
|
32
32
|
|
|
33
|
-
def _log(
|
|
33
|
+
def _log(
|
|
34
|
+
self,
|
|
35
|
+
ctx: CaptureLoggingContext,
|
|
36
|
+
msg: ta.Union[str, tuple, LoggingMsgFn],
|
|
37
|
+
*args: ta.Any,
|
|
38
|
+
) -> None:
|
|
34
39
|
if not self.is_enabled_for(ctx.must_get_info(LoggingContextInfos.Level).level):
|
|
35
40
|
return
|
|
36
41
|
|
omlish/logs/std/noisy.py
CHANGED
|
@@ -4,16 +4,18 @@ import logging
|
|
|
4
4
|
##
|
|
5
5
|
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
'boto3.resources.action',
|
|
9
|
-
'datadog.dogstatsd',
|
|
10
|
-
'elasticsearch',
|
|
11
|
-
'
|
|
12
|
-
'
|
|
13
|
-
'
|
|
7
|
+
NOISY_LOGGER_LEVELS: dict[str, int] = {
|
|
8
|
+
'boto3.resources.action': logging.WARNING,
|
|
9
|
+
'datadog.dogstatsd': logging.WARNING,
|
|
10
|
+
'elasticsearch': logging.WARNING,
|
|
11
|
+
'httpcore': logging.INFO,
|
|
12
|
+
'httpx': logging.WARNING,
|
|
13
|
+
'kazoo.client': logging.WARNING,
|
|
14
|
+
'markdown_it': logging.INFO,
|
|
15
|
+
'requests.packages.urllib3.connectionpool': logging.WARNING,
|
|
14
16
|
}
|
|
15
17
|
|
|
16
18
|
|
|
17
19
|
def silence_noisy_loggers() -> None:
|
|
18
|
-
for
|
|
19
|
-
logging.getLogger(
|
|
20
|
+
for name, level in NOISY_LOGGER_LEVELS.items():
|
|
21
|
+
logging.getLogger(name).setLevel(level)
|