dycw-utilities 0.129.14__py3-none-any.whl → 0.130.0__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.
- {dycw_utilities-0.129.14.dist-info → dycw_utilities-0.130.0.dist-info}/METADATA +26 -28
- {dycw_utilities-0.129.14.dist-info → dycw_utilities-0.130.0.dist-info}/RECORD +11 -13
- utilities/__init__.py +1 -1
- utilities/asyncio.py +9 -4
- utilities/logging.py +276 -498
- utilities/redis.py +3 -3
- utilities/sqlalchemy.py +8 -2
- utilities/sqlalchemy_polars.py +2 -2
- utilities/traceback.py +102 -901
- utilities/loguru.py +0 -144
- utilities/sys.py +0 -87
- {dycw_utilities-0.129.14.dist-info → dycw_utilities-0.130.0.dist-info}/WHEEL +0 -0
- {dycw_utilities-0.129.14.dist-info → dycw_utilities-0.130.0.dist-info}/licenses/LICENSE +0 -0
utilities/loguru.py
DELETED
@@ -1,144 +0,0 @@
|
|
1
|
-
from __future__ import annotations
|
2
|
-
|
3
|
-
import logging
|
4
|
-
from dataclasses import dataclass
|
5
|
-
from enum import StrEnum, unique
|
6
|
-
from logging import Handler, LogRecord
|
7
|
-
from sys import _getframe
|
8
|
-
from typing import TYPE_CHECKING, cast, override
|
9
|
-
|
10
|
-
from loguru import logger
|
11
|
-
|
12
|
-
from utilities.iterables import OneEmptyError, OneNonUniqueError, one
|
13
|
-
|
14
|
-
if TYPE_CHECKING:
|
15
|
-
from collections.abc import Sequence
|
16
|
-
|
17
|
-
from loguru import LevelConfig
|
18
|
-
|
19
|
-
|
20
|
-
LEVEL_CONFIGS: Sequence[LevelConfig] = [
|
21
|
-
{"name": "TRACE", "color": "<blue><bold>"},
|
22
|
-
{"name": "DEBUG", "color": "<cyan><bold>"},
|
23
|
-
{"name": "INFO", "color": "<green><bold>"},
|
24
|
-
{"name": "SUCCESS", "color": "<magenta><bold>"},
|
25
|
-
{"name": "WARNING", "color": "<yellow><bold>"},
|
26
|
-
{"name": "ERROR", "color": "<red><bold>"},
|
27
|
-
{"name": "CRITICAL", "color": "<red><bold><blink>"},
|
28
|
-
]
|
29
|
-
|
30
|
-
|
31
|
-
##
|
32
|
-
|
33
|
-
|
34
|
-
class InterceptHandler(Handler):
|
35
|
-
"""Handler for intercepting standard logging messages.
|
36
|
-
|
37
|
-
https://github.com/Delgan/loguru#entirely-compatible-with-standard-logging
|
38
|
-
"""
|
39
|
-
|
40
|
-
@override
|
41
|
-
def emit(self, record: LogRecord) -> None:
|
42
|
-
# Get corresponding Loguru level if it exists.
|
43
|
-
try: # pragma: no cover
|
44
|
-
level = logger.level(record.levelname).name
|
45
|
-
except ValueError: # pragma: no cover
|
46
|
-
level = record.levelno
|
47
|
-
|
48
|
-
# Find caller from where originated the logged message.
|
49
|
-
frame, depth = _getframe(6), 6 # pragma: no cover
|
50
|
-
while ( # pragma: no cover
|
51
|
-
frame and frame.f_code.co_filename == logging.__file__
|
52
|
-
):
|
53
|
-
frame = frame.f_back
|
54
|
-
depth += 1
|
55
|
-
|
56
|
-
logger.opt(depth=depth, exception=record.exc_info).log( # pragma: no cover
|
57
|
-
level, record.getMessage()
|
58
|
-
)
|
59
|
-
|
60
|
-
|
61
|
-
##
|
62
|
-
|
63
|
-
|
64
|
-
@unique
|
65
|
-
class LogLevel(StrEnum):
|
66
|
-
"""An enumeration of the logging levels."""
|
67
|
-
|
68
|
-
TRACE = "TRACE"
|
69
|
-
DEBUG = "DEBUG"
|
70
|
-
INFO = "INFO"
|
71
|
-
SUCCESS = "SUCCESS"
|
72
|
-
WARNING = "WARNING"
|
73
|
-
ERROR = "ERROR"
|
74
|
-
CRITICAL = "CRITICAL"
|
75
|
-
|
76
|
-
|
77
|
-
##
|
78
|
-
|
79
|
-
|
80
|
-
def get_logging_level_name(level: int, /) -> str:
|
81
|
-
"""Get the logging level name."""
|
82
|
-
core = logger._core # noqa: SLF001 # pyright: ignore[reportAttributeAccessIssue]
|
83
|
-
try:
|
84
|
-
return one(k for k, v in core.levels.items() if v.no == level)
|
85
|
-
except OneEmptyError:
|
86
|
-
raise _GetLoggingLevelNameEmptyError(level=level) from None
|
87
|
-
except OneNonUniqueError as error:
|
88
|
-
error = cast("OneNonUniqueError[str]", error)
|
89
|
-
raise _GetLoggingLevelNameNonUniqueError(
|
90
|
-
level=level, first=error.first, second=error.second
|
91
|
-
) from None
|
92
|
-
|
93
|
-
|
94
|
-
@dataclass(kw_only=True, slots=True)
|
95
|
-
class GetLoggingLevelNameError(Exception):
|
96
|
-
level: int
|
97
|
-
|
98
|
-
|
99
|
-
@dataclass(kw_only=True, slots=True)
|
100
|
-
class _GetLoggingLevelNameEmptyError(GetLoggingLevelNameError):
|
101
|
-
@override
|
102
|
-
def __str__(self) -> str:
|
103
|
-
return f"There is no level with severity {self.level}"
|
104
|
-
|
105
|
-
|
106
|
-
@dataclass(kw_only=True, slots=True)
|
107
|
-
class _GetLoggingLevelNameNonUniqueError(GetLoggingLevelNameError):
|
108
|
-
first: str
|
109
|
-
second: str
|
110
|
-
|
111
|
-
@override
|
112
|
-
def __str__(self) -> str:
|
113
|
-
return f"There must be exactly one level with severity {self.level}; got {self.first!r}, {self.second!r} and perhaps more"
|
114
|
-
|
115
|
-
|
116
|
-
##
|
117
|
-
|
118
|
-
|
119
|
-
def get_logging_level_number(level: str, /) -> int:
|
120
|
-
"""Get the logging level number."""
|
121
|
-
try:
|
122
|
-
return logger.level(level).no
|
123
|
-
except ValueError:
|
124
|
-
raise GetLoggingLevelNumberError(level=level) from None
|
125
|
-
|
126
|
-
|
127
|
-
@dataclass(kw_only=True, slots=True)
|
128
|
-
class GetLoggingLevelNumberError(Exception):
|
129
|
-
level: str
|
130
|
-
|
131
|
-
@override
|
132
|
-
def __str__(self) -> str:
|
133
|
-
return f"Invalid logging level: {self.level!r}"
|
134
|
-
|
135
|
-
|
136
|
-
__all__ = [
|
137
|
-
"LEVEL_CONFIGS",
|
138
|
-
"GetLoggingLevelNameError",
|
139
|
-
"GetLoggingLevelNumberError",
|
140
|
-
"InterceptHandler",
|
141
|
-
"LogLevel",
|
142
|
-
"get_logging_level_name",
|
143
|
-
"get_logging_level_number",
|
144
|
-
]
|
utilities/sys.py
DELETED
@@ -1,87 +0,0 @@
|
|
1
|
-
from __future__ import annotations
|
2
|
-
|
3
|
-
from asyncio import TaskGroup, run
|
4
|
-
from dataclasses import dataclass
|
5
|
-
from functools import partial
|
6
|
-
from inspect import iscoroutinefunction
|
7
|
-
from sys import version_info
|
8
|
-
from typing import TYPE_CHECKING, Any, cast, override
|
9
|
-
|
10
|
-
from utilities.logging import get_logger
|
11
|
-
|
12
|
-
if TYPE_CHECKING:
|
13
|
-
from collections.abc import Callable, Iterable
|
14
|
-
from types import TracebackType
|
15
|
-
|
16
|
-
from utilities.types import Coroutine1, LoggerOrName, MaybeCoroutine1, StrMapping
|
17
|
-
|
18
|
-
|
19
|
-
VERSION_MAJOR_MINOR = (version_info.major, version_info.minor)
|
20
|
-
|
21
|
-
|
22
|
-
def make_except_hook(
|
23
|
-
*,
|
24
|
-
logger: LoggerOrName | None = None,
|
25
|
-
message: object = "",
|
26
|
-
extra: StrMapping | None = None,
|
27
|
-
callbacks: Iterable[Callable[[], MaybeCoroutine1[None]]] | None = None,
|
28
|
-
) -> Callable[
|
29
|
-
[type[BaseException] | None, BaseException | None, TracebackType | None], None
|
30
|
-
]:
|
31
|
-
"""Create an exception hook with various features."""
|
32
|
-
return partial(
|
33
|
-
_make_except_hook_inner,
|
34
|
-
logger=logger,
|
35
|
-
message=message,
|
36
|
-
extra=extra,
|
37
|
-
callbacks=callbacks,
|
38
|
-
)
|
39
|
-
|
40
|
-
|
41
|
-
def _make_except_hook_inner(
|
42
|
-
exc_type: type[BaseException] | None,
|
43
|
-
exc_val: BaseException | None,
|
44
|
-
traceback: TracebackType | None,
|
45
|
-
/,
|
46
|
-
*,
|
47
|
-
logger: LoggerOrName | None = None,
|
48
|
-
message: object = "",
|
49
|
-
extra: StrMapping | None = None,
|
50
|
-
callbacks: Iterable[Callable[[], MaybeCoroutine1[None]]] | None = None,
|
51
|
-
) -> None:
|
52
|
-
"""Exception hook to log the traceback."""
|
53
|
-
_ = (exc_type, traceback)
|
54
|
-
if exc_val is None:
|
55
|
-
raise MakeExceptHookError
|
56
|
-
logger_use = get_logger(logger=logger)
|
57
|
-
exc_info = (exc_type, exc_val, traceback)
|
58
|
-
logger_use.exception(message, exc_info=cast("Any", exc_info), extra=extra)
|
59
|
-
async_callbacks: list[Callable[[], Coroutine1[None]]] = []
|
60
|
-
if callbacks is not None:
|
61
|
-
for callback in callbacks:
|
62
|
-
if not iscoroutinefunction(callback):
|
63
|
-
cast("Callable[[], None]", callback)()
|
64
|
-
else: # skipif-ci
|
65
|
-
async_callback = cast("Callable[[], Coroutine1[None]]", callback)
|
66
|
-
async_callbacks.append(async_callback)
|
67
|
-
if len(async_callbacks) >= 1: # skipif-ci
|
68
|
-
run(_run_async_callbacks(async_callbacks))
|
69
|
-
|
70
|
-
|
71
|
-
@dataclass(kw_only=True, slots=True)
|
72
|
-
class MakeExceptHookError(Exception):
|
73
|
-
@override
|
74
|
-
def __str__(self) -> str:
|
75
|
-
return "No exception to log"
|
76
|
-
|
77
|
-
|
78
|
-
async def _run_async_callbacks(
|
79
|
-
callbacks: Iterable[Callable[[], Coroutine1[None]]], /
|
80
|
-
) -> None:
|
81
|
-
"""Run all asynchronous callbacks."""
|
82
|
-
async with TaskGroup() as tg: # skipif-ci
|
83
|
-
for callback in callbacks:
|
84
|
-
_ = tg.create_task(callback())
|
85
|
-
|
86
|
-
|
87
|
-
__all__ = ["VERSION_MAJOR_MINOR", "MakeExceptHookError", "make_except_hook"]
|
File without changes
|
File without changes
|