dycw-utilities 0.126.10__py3-none-any.whl → 0.126.12__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.126.10.dist-info → dycw_utilities-0.126.12.dist-info}/METADATA +1 -1
- {dycw_utilities-0.126.10.dist-info → dycw_utilities-0.126.12.dist-info}/RECORD +9 -10
- utilities/__init__.py +1 -1
- utilities/redis.py +115 -5
- utilities/reprlib.py +85 -1
- utilities/sqlalchemy.py +65 -1
- utilities/traceback.py +3 -5
- utilities/rich.py +0 -74
- {dycw_utilities-0.126.10.dist-info → dycw_utilities-0.126.12.dist-info}/WHEEL +0 -0
- {dycw_utilities-0.126.10.dist-info → dycw_utilities-0.126.12.dist-info}/licenses/LICENSE +0 -0
@@ -1,4 +1,4 @@
|
|
1
|
-
utilities/__init__.py,sha256=
|
1
|
+
utilities/__init__.py,sha256=w7Bw5b1ygtU74n1HhymesHdGAgm2zjsVhaI-oN62x8k,61
|
2
2
|
utilities/altair.py,sha256=Gpja-flOo-Db0PIPJLJsgzAlXWoKUjPU1qY-DQ829ek,9156
|
3
3
|
utilities/asyncio.py,sha256=phbGti22VSe9cu-SwM1vP8kyUg8AUDHvvciMvE6JnCg,51842
|
4
4
|
utilities/atomicwrites.py,sha256=geFjn9Pwn-tTrtoGjDDxWli9NqbYfy3gGL6ZBctiqSo,5393
|
@@ -61,15 +61,14 @@ utilities/pytest_regressions.py,sha256=-SVT9647Dg6-JcdsiaDKXe3NdOmmrvGevLKWwGjxq
|
|
61
61
|
utilities/python_dotenv.py,sha256=iWcnpXbH7S6RoXHiLlGgyuH6udCupAcPd_gQ0eAenQ0,3190
|
62
62
|
utilities/random.py,sha256=lYdjgxB7GCfU_fwFVl5U-BIM_HV3q6_urL9byjrwDM8,4157
|
63
63
|
utilities/re.py,sha256=5J4d8VwIPFVrX2Eb8zfoxImDv7IwiN_U7mJ07wR2Wvs,3958
|
64
|
-
utilities/redis.py,sha256=
|
65
|
-
utilities/reprlib.py,sha256=
|
66
|
-
utilities/rich.py,sha256=t50MwwVBsoOLxzmeVFSVpjno4OW6Ufum32skXbV8-Bs,1911
|
64
|
+
utilities/redis.py,sha256=pMKJjNI5e0lG-FZh2_idMBBmfgNr53KIGjBquZQOLZc,37556
|
65
|
+
utilities/reprlib.py,sha256=ssYTcBW-TeRh3fhCJv57sopTZHF5FrPyyUg9yp5XBlo,3953
|
67
66
|
utilities/scipy.py,sha256=X6ROnHwiUhAmPhM0jkfEh0-Fd9iRvwiqtCQMOLmOQF8,945
|
68
67
|
utilities/sentinel.py,sha256=3jIwgpMekWgDAxPDA_hXMP2St43cPhciKN3LWiZ7kv0,1248
|
69
68
|
utilities/shelve.py,sha256=HZsMwK4tcIfg3sh0gApx4-yjQnrY4o3V3ZRimvRhoW0,738
|
70
69
|
utilities/slack_sdk.py,sha256=h2DiVkcFyYcT5zzZOAo6CSith5BBlHUbXeOJSL1neK8,5948
|
71
70
|
utilities/socket.py,sha256=K77vfREvzoVTrpYKo6MZakol0EYu2q1sWJnnZqL0So0,118
|
72
|
-
utilities/sqlalchemy.py,sha256=
|
71
|
+
utilities/sqlalchemy.py,sha256=rHixzaYl_QHTR1dAhLj15ntiE5kwZWY4MKIr97crDts,39602
|
73
72
|
utilities/sqlalchemy_polars.py,sha256=s7hQNep2O5DTgIRXyN_JRQma7a4DAtNd25tshaZW8iw,15490
|
74
73
|
utilities/statsmodels.py,sha256=koyiBHvpMcSiBfh99wFUfSggLNx7cuAw3rwyfAhoKpQ,3410
|
75
74
|
utilities/streamlit.py,sha256=U9PJBaKP1IdSykKhPZhIzSPTZsmLsnwbEPZWzNhJPKk,2955
|
@@ -80,7 +79,7 @@ utilities/tenacity.py,sha256=1PUvODiBVgeqIh7G5TRt5WWMSqjLYkEqP53itT97WQc,4914
|
|
80
79
|
utilities/text.py,sha256=ymBFlP_cA8OgNnZRVNs7FAh7OG8HxE6YkiLEMZv5g_A,11297
|
81
80
|
utilities/threading.py,sha256=GvBOp4CyhHfN90wGXZuA2VKe9fGzMaEa7oCl4f3nnPU,1009
|
82
81
|
utilities/timer.py,sha256=Rkc49KSpHuC8s7vUxGO9DU55U9I6yDKnchsQqrUCVBs,4075
|
83
|
-
utilities/traceback.py,sha256=
|
82
|
+
utilities/traceback.py,sha256=Jg7HS3AwQ-W-msdwHp22_PSHZcR54PbmsSf115B6TSM,27435
|
84
83
|
utilities/types.py,sha256=2f1DqTZTMRlpCPWPd9-rh_uwmRPv9UdBoi_Bfv7Ccmo,18374
|
85
84
|
utilities/typing.py,sha256=H6ysJkI830aRwLsMKz0SZIw4cpcsm7d6KhQOwr-SDh0,13817
|
86
85
|
utilities/tzdata.py,sha256=yCf70NICwAeazN3_JcXhWvRqCy06XJNQ42j7r6gw3HY,1217
|
@@ -91,7 +90,7 @@ utilities/warnings.py,sha256=un1LvHv70PU-LLv8RxPVmugTzDJkkGXRMZTE2-fTQHw,1771
|
|
91
90
|
utilities/whenever.py,sha256=jS31ZAY5OMxFxLja_Yo5Fidi87Pd-GoVZ7Vi_teqVDA,16743
|
92
91
|
utilities/zipfile.py,sha256=24lQc9ATcJxHXBPc_tBDiJk48pWyRrlxO2fIsFxU0A8,699
|
93
92
|
utilities/zoneinfo.py,sha256=-5j7IQ9nb7gR43rdgA7ms05im-XuqhAk9EJnQBXxCoQ,1874
|
94
|
-
dycw_utilities-0.126.
|
95
|
-
dycw_utilities-0.126.
|
96
|
-
dycw_utilities-0.126.
|
97
|
-
dycw_utilities-0.126.
|
93
|
+
dycw_utilities-0.126.12.dist-info/METADATA,sha256=T67klINutEoVWEiFhEoBupDjKUnBGBXokIa1or-nWfI,12804
|
94
|
+
dycw_utilities-0.126.12.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
95
|
+
dycw_utilities-0.126.12.dist-info/licenses/LICENSE,sha256=gppZp16M6nSVpBbUBrNL6JuYfvKwZiKgV7XoKKsHzqo,1066
|
96
|
+
dycw_utilities-0.126.12.dist-info/RECORD,,
|
utilities/__init__.py
CHANGED
utilities/redis.py
CHANGED
@@ -25,7 +25,14 @@ from typing import (
|
|
25
25
|
from redis.asyncio import Redis
|
26
26
|
from redis.typing import EncodableT
|
27
27
|
|
28
|
-
from utilities.asyncio import
|
28
|
+
from utilities.asyncio import (
|
29
|
+
EnhancedQueue,
|
30
|
+
InfiniteQueueLooper,
|
31
|
+
Looper,
|
32
|
+
LooperTimeoutError,
|
33
|
+
timeout_dur,
|
34
|
+
)
|
35
|
+
from utilities.contextlib import suppress_super_object_attribute_error
|
29
36
|
from utilities.datetime import (
|
30
37
|
MILLISECOND,
|
31
38
|
SECOND,
|
@@ -72,6 +79,9 @@ _V2 = TypeVar("_V2")
|
|
72
79
|
_V3 = TypeVar("_V3")
|
73
80
|
|
74
81
|
|
82
|
+
_PUBLISH_TIMEOUT: Duration = SECOND
|
83
|
+
|
84
|
+
|
75
85
|
##
|
76
86
|
|
77
87
|
|
@@ -548,9 +558,6 @@ def redis_key(
|
|
548
558
|
##
|
549
559
|
|
550
560
|
|
551
|
-
_PUBLISH_TIMEOUT: Duration = SECOND
|
552
|
-
|
553
|
-
|
554
561
|
@overload
|
555
562
|
async def publish(
|
556
563
|
redis: Redis,
|
@@ -666,7 +673,7 @@ class PublishService(Looper[tuple[str, _T]]):
|
|
666
673
|
# self
|
667
674
|
redis: Redis
|
668
675
|
serializer: Callable[[_T], EncodableT] = serialize
|
669
|
-
publish_timeout: Duration =
|
676
|
+
publish_timeout: Duration = _PUBLISH_TIMEOUT
|
670
677
|
|
671
678
|
@override
|
672
679
|
async def core(self) -> None:
|
@@ -685,6 +692,55 @@ class PublishService(Looper[tuple[str, _T]]):
|
|
685
692
|
##
|
686
693
|
|
687
694
|
|
695
|
+
@dataclass(kw_only=True)
|
696
|
+
class PublishServiceMixin(Generic[_T]):
|
697
|
+
"""Mix-in for the publish service."""
|
698
|
+
|
699
|
+
# base - looper
|
700
|
+
publish_service_freq: Duration = field(default=MILLISECOND, repr=False)
|
701
|
+
publish_service_backoff: Duration = field(default=SECOND, repr=False)
|
702
|
+
publish_service_empty_upon_exit: bool = field(default=False, repr=False)
|
703
|
+
publish_service_logger: str | None = field(default=None, repr=False)
|
704
|
+
publish_service_timeout: Duration | None = field(default=None, repr=False)
|
705
|
+
publish_service_timeout_error: type[Exception] = field(
|
706
|
+
default=LooperTimeoutError, repr=False
|
707
|
+
)
|
708
|
+
publish_service_debug: bool = field(default=False, repr=False)
|
709
|
+
_is_pending_restart: Event = field(default_factory=Event, init=False, repr=False)
|
710
|
+
# base - publish service
|
711
|
+
publish_service_redis: Redis
|
712
|
+
publish_service_serializer: Callable[[_T], EncodableT] = serialize
|
713
|
+
publish_service_publish_timeout: Duration = _PUBLISH_TIMEOUT
|
714
|
+
# self
|
715
|
+
_publish_service: PublishService[_T] = field(init=False, repr=False)
|
716
|
+
|
717
|
+
def __post_init__(self) -> None:
|
718
|
+
with suppress_super_object_attribute_error(): # skipif-ci-and-not-linux
|
719
|
+
super().__post_init__() # pyright: ignore[reportAttributeAccessIssue]
|
720
|
+
self._publish_service = PublishService( # skipif-ci-and-not-linux
|
721
|
+
# looper
|
722
|
+
freq=self.publish_service_freq,
|
723
|
+
backoff=self.publish_service_backoff,
|
724
|
+
empty_upon_exit=self.publish_service_empty_upon_exit,
|
725
|
+
logger=self.publish_service_logger,
|
726
|
+
timeout=self.publish_service_timeout,
|
727
|
+
timeout_error=self.publish_service_timeout_error,
|
728
|
+
_debug=self.publish_service_debug,
|
729
|
+
# publish service
|
730
|
+
redis=self.publish_service_redis,
|
731
|
+
serializer=self.publish_service_serializer,
|
732
|
+
publish_timeout=self.publish_service_publish_timeout,
|
733
|
+
)
|
734
|
+
|
735
|
+
def _yield_sub_loopers(self) -> Iterator[Looper[Any]]:
|
736
|
+
with suppress_super_object_attribute_error(): # skipif-ci-and-not-linux
|
737
|
+
yield from super()._yield_sub_loopers() # pyright: ignore[reportAttributeAccessIssue]
|
738
|
+
yield self._publish_service # skipif-ci-and-not-linux
|
739
|
+
|
740
|
+
|
741
|
+
##
|
742
|
+
|
743
|
+
|
688
744
|
_SUBSCRIBE_TIMEOUT: Duration = SECOND
|
689
745
|
_SUBSCRIBE_SLEEP: Duration = MILLISECOND
|
690
746
|
|
@@ -920,6 +976,58 @@ class SubscribeService(Looper[_T]):
|
|
920
976
|
##
|
921
977
|
|
922
978
|
|
979
|
+
@dataclass(kw_only=True)
|
980
|
+
class SubscribeServiceMixin(Generic[_T]):
|
981
|
+
"""Mix-in for the subscribe service."""
|
982
|
+
|
983
|
+
# base - looper
|
984
|
+
subscribe_service_freq: Duration = field(default=MILLISECOND, repr=False)
|
985
|
+
subscribe_service_backoff: Duration = field(default=SECOND, repr=False)
|
986
|
+
subscribe_service_empty_upon_exit: bool = field(default=False, repr=False)
|
987
|
+
subscribe_service_logger: str | None = field(default=None, repr=False)
|
988
|
+
subscribe_service_timeout: Duration | None = field(default=None, repr=False)
|
989
|
+
subscribe_service_timeout_error: type[Exception] = field(
|
990
|
+
default=LooperTimeoutError, repr=False
|
991
|
+
)
|
992
|
+
subscribe_service_debug: bool = field(default=False, repr=False)
|
993
|
+
# base - looper
|
994
|
+
subscribe_service_redis: Redis
|
995
|
+
subscribe_service_channel: str
|
996
|
+
subscribe_service_deserializer: Callable[[bytes], _T] = deserialize
|
997
|
+
subscribe_service_subscribe_sleep: Duration = _SUBSCRIBE_SLEEP
|
998
|
+
subscribe_service_subscribe_timeout: Duration | None = _SUBSCRIBE_TIMEOUT
|
999
|
+
# self
|
1000
|
+
_subscribe_service: SubscribeService[_T] = field(init=False, repr=False)
|
1001
|
+
|
1002
|
+
def __post_init__(self) -> None:
|
1003
|
+
with suppress_super_object_attribute_error(): # skipif-ci-and-not-linux
|
1004
|
+
super().__post_init__() # pyright: ignore[reportAttributeAccessIssue]
|
1005
|
+
self._subscribe_service = SubscribeService( # skipif-ci-and-not-linux
|
1006
|
+
# looper
|
1007
|
+
freq=self.subscribe_service_freq,
|
1008
|
+
backoff=self.subscribe_service_backoff,
|
1009
|
+
empty_upon_exit=self.subscribe_service_empty_upon_exit,
|
1010
|
+
logger=self.subscribe_service_logger,
|
1011
|
+
timeout=self.subscribe_service_timeout,
|
1012
|
+
timeout_error=self.subscribe_service_timeout_error,
|
1013
|
+
_debug=self.subscribe_service_debug,
|
1014
|
+
# subscribe service
|
1015
|
+
redis=self.subscribe_service_redis,
|
1016
|
+
channel=self.subscribe_service_channel,
|
1017
|
+
deserializer=self.subscribe_service_deserializer,
|
1018
|
+
subscribe_sleep=self.subscribe_service_subscribe_sleep,
|
1019
|
+
subscribe_timeout=self.subscribe_service_subscribe_timeout,
|
1020
|
+
)
|
1021
|
+
|
1022
|
+
def _yield_sub_loopers(self) -> Iterator[Looper[Any]]:
|
1023
|
+
with suppress_super_object_attribute_error(): # skipif-ci-and-not-linux
|
1024
|
+
yield from super()._yield_sub_loopers() # pyright: ignore[reportAttributeAccessIssue]
|
1025
|
+
yield self._subscribe_service # skipif-ci-and-not-linux
|
1026
|
+
|
1027
|
+
|
1028
|
+
##
|
1029
|
+
|
1030
|
+
|
923
1031
|
@asynccontextmanager
|
924
1032
|
async def yield_pubsub(
|
925
1033
|
redis: Redis, channels: MaybeIterable[str], /
|
@@ -1000,11 +1108,13 @@ def _deserialize(
|
|
1000
1108
|
|
1001
1109
|
__all__ = [
|
1002
1110
|
"PublishService",
|
1111
|
+
"PublishServiceMixin",
|
1003
1112
|
"Publisher",
|
1004
1113
|
"PublisherError",
|
1005
1114
|
"RedisHashMapKey",
|
1006
1115
|
"RedisKey",
|
1007
1116
|
"SubscribeService",
|
1117
|
+
"SubscribeServiceMixin",
|
1008
1118
|
"publish",
|
1009
1119
|
"redis_hash_map_key",
|
1010
1120
|
"redis_key",
|
utilities/reprlib.py
CHANGED
@@ -1,7 +1,13 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
3
|
import reprlib
|
4
|
-
from
|
4
|
+
from functools import partial
|
5
|
+
from typing import TYPE_CHECKING, Any
|
6
|
+
|
7
|
+
if TYPE_CHECKING:
|
8
|
+
from collections.abc import Iterator
|
9
|
+
|
10
|
+
from utilities.types import StrMapping
|
5
11
|
|
6
12
|
RICH_MAX_WIDTH: int = 80
|
7
13
|
RICH_INDENT_SIZE: int = 4
|
@@ -11,6 +17,19 @@ RICH_MAX_DEPTH: int | None = None
|
|
11
17
|
RICH_EXPAND_ALL: bool = False
|
12
18
|
|
13
19
|
|
20
|
+
##
|
21
|
+
|
22
|
+
|
23
|
+
def get_call_args_mapping(*args: Any, **kwargs: Any) -> StrMapping:
|
24
|
+
"""Get the representation of a set of call arguments."""
|
25
|
+
return {f"args[{i}]": v for i, v in enumerate(args)} | {
|
26
|
+
f"kwargs[{k}]": v for k, v in kwargs.items()
|
27
|
+
}
|
28
|
+
|
29
|
+
|
30
|
+
##
|
31
|
+
|
32
|
+
|
14
33
|
def get_repr(
|
15
34
|
obj: Any,
|
16
35
|
/,
|
@@ -38,6 +57,9 @@ def get_repr(
|
|
38
57
|
)
|
39
58
|
|
40
59
|
|
60
|
+
##
|
61
|
+
|
62
|
+
|
41
63
|
def get_repr_and_class(
|
42
64
|
obj: Any,
|
43
65
|
/,
|
@@ -62,6 +84,65 @@ def get_repr_and_class(
|
|
62
84
|
return f"Object {repr_use!r} of type {type(obj).__name__!r}"
|
63
85
|
|
64
86
|
|
87
|
+
##
|
88
|
+
|
89
|
+
|
90
|
+
def yield_call_args_repr(
|
91
|
+
*args: Any,
|
92
|
+
_max_width: int = RICH_MAX_WIDTH,
|
93
|
+
_indent_size: int = RICH_INDENT_SIZE,
|
94
|
+
_max_length: int | None = RICH_MAX_LENGTH,
|
95
|
+
_max_string: int | None = RICH_MAX_STRING,
|
96
|
+
_max_depth: int | None = RICH_MAX_DEPTH,
|
97
|
+
_expand_all: bool = RICH_EXPAND_ALL,
|
98
|
+
**kwargs: Any,
|
99
|
+
) -> Iterator[str]:
|
100
|
+
"""Pretty print of a set of positional/keyword arguments."""
|
101
|
+
mapping = get_call_args_mapping(*args, **kwargs)
|
102
|
+
return yield_mapping_repr(
|
103
|
+
mapping,
|
104
|
+
_max_width=_max_width,
|
105
|
+
_indent_size=_indent_size,
|
106
|
+
_max_length=_max_length,
|
107
|
+
_max_string=_max_string,
|
108
|
+
_max_depth=_max_depth,
|
109
|
+
_expand_all=_expand_all,
|
110
|
+
)
|
111
|
+
|
112
|
+
|
113
|
+
##
|
114
|
+
|
115
|
+
|
116
|
+
def yield_mapping_repr(
|
117
|
+
mapping: StrMapping,
|
118
|
+
/,
|
119
|
+
*,
|
120
|
+
_max_width: int = RICH_MAX_WIDTH,
|
121
|
+
_indent_size: int = RICH_INDENT_SIZE,
|
122
|
+
_max_length: int | None = RICH_MAX_LENGTH,
|
123
|
+
_max_string: int | None = RICH_MAX_STRING,
|
124
|
+
_max_depth: int | None = RICH_MAX_DEPTH,
|
125
|
+
_expand_all: bool = RICH_EXPAND_ALL,
|
126
|
+
) -> Iterator[str]:
|
127
|
+
"""Pretty print of a set of keyword arguments."""
|
128
|
+
try:
|
129
|
+
from rich.pretty import pretty_repr
|
130
|
+
except ModuleNotFoundError: # pragma: no cover
|
131
|
+
repr_use = repr
|
132
|
+
else:
|
133
|
+
repr_use = partial(
|
134
|
+
pretty_repr,
|
135
|
+
max_width=_max_width,
|
136
|
+
indent_size=_indent_size,
|
137
|
+
max_length=_max_length,
|
138
|
+
max_string=_max_string,
|
139
|
+
max_depth=_max_depth,
|
140
|
+
expand_all=_expand_all,
|
141
|
+
)
|
142
|
+
for k, v in mapping.items():
|
143
|
+
yield f"{k} = {repr_use(v)}"
|
144
|
+
|
145
|
+
|
65
146
|
__all__ = [
|
66
147
|
"RICH_EXPAND_ALL",
|
67
148
|
"RICH_INDENT_SIZE",
|
@@ -69,6 +150,9 @@ __all__ = [
|
|
69
150
|
"RICH_MAX_LENGTH",
|
70
151
|
"RICH_MAX_STRING",
|
71
152
|
"RICH_MAX_WIDTH",
|
153
|
+
"get_call_args_mapping",
|
72
154
|
"get_repr",
|
73
155
|
"get_repr_and_class",
|
156
|
+
"yield_call_args_repr",
|
157
|
+
"yield_mapping_repr",
|
74
158
|
]
|
utilities/sqlalchemy.py
CHANGED
@@ -57,7 +57,13 @@ from sqlalchemy.orm import (
|
|
57
57
|
from sqlalchemy.orm.exc import UnmappedClassError
|
58
58
|
from sqlalchemy.pool import NullPool, Pool
|
59
59
|
|
60
|
-
from utilities.asyncio import
|
60
|
+
from utilities.asyncio import (
|
61
|
+
InfiniteQueueLooper,
|
62
|
+
Looper,
|
63
|
+
LooperTimeoutError,
|
64
|
+
timeout_dur,
|
65
|
+
)
|
66
|
+
from utilities.contextlib import suppress_super_object_attribute_error
|
61
67
|
from utilities.datetime import SECOND
|
62
68
|
from utilities.functions import (
|
63
69
|
ensure_str,
|
@@ -691,6 +697,63 @@ class UpsertService(Looper[_InsertItem]):
|
|
691
697
|
)
|
692
698
|
|
693
699
|
|
700
|
+
@dataclass(kw_only=True)
|
701
|
+
class UpsertServiceMixin:
|
702
|
+
"""Mix-in for the upsert service."""
|
703
|
+
|
704
|
+
# base - looper
|
705
|
+
upsert_service_freq: Duration = field(default=SECOND, repr=False)
|
706
|
+
upsert_service_backoff: Duration = field(default=SECOND, repr=False)
|
707
|
+
upsert_service_empty_upon_exit: bool = field(default=False, repr=False)
|
708
|
+
upsert_service_logger: str | None = field(default=None, repr=False)
|
709
|
+
upsert_service_timeout: Duration | None = field(default=None, repr=False)
|
710
|
+
upsert_service_timeout_error: type[Exception] = field(
|
711
|
+
default=LooperTimeoutError, repr=False
|
712
|
+
)
|
713
|
+
upsert_service_debug: bool = field(default=False, repr=False)
|
714
|
+
# base - upsert service
|
715
|
+
upsert_service_database: AsyncEngine
|
716
|
+
upsert_service_snake: bool = False
|
717
|
+
upsert_service_selected_or_all: _SelectedOrAll = "selected"
|
718
|
+
upsert_service_chunk_size_frac: float = CHUNK_SIZE_FRAC
|
719
|
+
upsert_service_assume_tables_exist: bool = False
|
720
|
+
upsert_service_timeout_create: Duration | None = None
|
721
|
+
upsert_service_error_create: type[Exception] = TimeoutError
|
722
|
+
upsert_service_timeout_insert: Duration | None = None
|
723
|
+
upsert_service_error_insert: type[Exception] = TimeoutError
|
724
|
+
# self
|
725
|
+
_upsert_service: UpsertService = field(init=False, repr=False)
|
726
|
+
|
727
|
+
def __post_init__(self) -> None:
|
728
|
+
with suppress_super_object_attribute_error():
|
729
|
+
super().__post_init__() # pyright: ignore[reportAttributeAccessIssue]
|
730
|
+
self._upsert_service = UpsertService(
|
731
|
+
# looper
|
732
|
+
freq=self.upsert_service_freq,
|
733
|
+
backoff=self.upsert_service_backoff,
|
734
|
+
empty_upon_exit=self.upsert_service_empty_upon_exit,
|
735
|
+
logger=self.upsert_service_logger,
|
736
|
+
timeout=self.upsert_service_timeout,
|
737
|
+
timeout_error=self.upsert_service_timeout_error,
|
738
|
+
_debug=self.upsert_service_debug,
|
739
|
+
# upsert service
|
740
|
+
engine=self.upsert_service_database,
|
741
|
+
snake=self.upsert_service_snake,
|
742
|
+
selected_or_all=self.upsert_service_selected_or_all,
|
743
|
+
chunk_size_frac=self.upsert_service_chunk_size_frac,
|
744
|
+
assume_tables_exist=self.upsert_service_assume_tables_exist,
|
745
|
+
timeout_create=self.upsert_service_timeout_create,
|
746
|
+
error_create=self.upsert_service_error_create,
|
747
|
+
timeout_insert=self.upsert_service_timeout_insert,
|
748
|
+
error_insert=self.upsert_service_error_insert,
|
749
|
+
)
|
750
|
+
|
751
|
+
def _yield_sub_loopers(self) -> Iterator[Looper[Any]]:
|
752
|
+
with suppress_super_object_attribute_error():
|
753
|
+
yield from super()._yield_sub_loopers() # pyright: ignore[reportAttributeAccessIssue]
|
754
|
+
yield self._upsert_service
|
755
|
+
|
756
|
+
|
694
757
|
##
|
695
758
|
|
696
759
|
|
@@ -1147,6 +1210,7 @@ __all__ = [
|
|
1147
1210
|
"TablenameMixin",
|
1148
1211
|
"UpsertItemsError",
|
1149
1212
|
"UpsertService",
|
1213
|
+
"UpsertServiceMixin",
|
1150
1214
|
"Upserter",
|
1151
1215
|
"UpserterError",
|
1152
1216
|
"check_engine",
|
utilities/traceback.py
CHANGED
@@ -42,6 +42,8 @@ from utilities.reprlib import (
|
|
42
42
|
RICH_MAX_LENGTH,
|
43
43
|
RICH_MAX_STRING,
|
44
44
|
RICH_MAX_WIDTH,
|
45
|
+
yield_call_args_repr,
|
46
|
+
yield_mapping_repr,
|
45
47
|
)
|
46
48
|
from utilities.types import TBaseException, TCallable
|
47
49
|
from utilities.version import get_version
|
@@ -199,8 +201,6 @@ class _CallArgs:
|
|
199
201
|
@classmethod
|
200
202
|
def create(cls, func: Callable[..., Any], *args: Any, **kwargs: Any) -> Self:
|
201
203
|
"""Make the initial trace data."""
|
202
|
-
from utilities.rich import yield_call_args_repr
|
203
|
-
|
204
204
|
sig = signature(func)
|
205
205
|
try:
|
206
206
|
bound_args = sig.bind(*args, **kwargs)
|
@@ -437,8 +437,6 @@ class _Frame:
|
|
437
437
|
depth: int = 0,
|
438
438
|
) -> str:
|
439
439
|
"""Format the traceback."""
|
440
|
-
from utilities.rich import yield_call_args_repr, yield_mapping_repr
|
441
|
-
|
442
440
|
lines: list[str] = [f"Frame {index + 1}/{total}: {self.name} ({self.module})"]
|
443
441
|
if detail:
|
444
442
|
lines.append(indent("Inputs:", _INDENT))
|
@@ -459,13 +457,13 @@ class _Frame:
|
|
459
457
|
lines.extend(
|
460
458
|
indent(line, 2 * _INDENT)
|
461
459
|
for line in yield_mapping_repr(
|
460
|
+
self.locals,
|
462
461
|
_max_width=self.max_width,
|
463
462
|
_indent_size=self.indent_size,
|
464
463
|
_max_length=self.max_length,
|
465
464
|
_max_string=self.max_string,
|
466
465
|
_max_depth=self.max_depth,
|
467
466
|
_expand_all=self.expand_all,
|
468
|
-
**self.locals,
|
469
467
|
)
|
470
468
|
)
|
471
469
|
lines.extend([
|
utilities/rich.py
DELETED
@@ -1,74 +0,0 @@
|
|
1
|
-
from __future__ import annotations
|
2
|
-
|
3
|
-
from typing import TYPE_CHECKING, Any
|
4
|
-
|
5
|
-
from rich.pretty import pretty_repr
|
6
|
-
|
7
|
-
from utilities.reprlib import (
|
8
|
-
RICH_EXPAND_ALL,
|
9
|
-
RICH_INDENT_SIZE,
|
10
|
-
RICH_MAX_DEPTH,
|
11
|
-
RICH_MAX_LENGTH,
|
12
|
-
RICH_MAX_STRING,
|
13
|
-
RICH_MAX_WIDTH,
|
14
|
-
)
|
15
|
-
|
16
|
-
if TYPE_CHECKING:
|
17
|
-
from collections.abc import Iterator
|
18
|
-
|
19
|
-
|
20
|
-
##
|
21
|
-
|
22
|
-
|
23
|
-
def yield_call_args_repr(
|
24
|
-
*args: Any,
|
25
|
-
_max_width: int = RICH_MAX_WIDTH,
|
26
|
-
_indent_size: int = RICH_INDENT_SIZE,
|
27
|
-
_max_length: int | None = RICH_MAX_LENGTH,
|
28
|
-
_max_string: int | None = RICH_MAX_STRING,
|
29
|
-
_max_depth: int | None = RICH_MAX_DEPTH,
|
30
|
-
_expand_all: bool = RICH_EXPAND_ALL,
|
31
|
-
**kwargs: Any,
|
32
|
-
) -> Iterator[str]:
|
33
|
-
"""Pretty print of a set of positional/keyword arguments."""
|
34
|
-
mapping = {f"args[{i}]": v for i, v in enumerate(args)} | {
|
35
|
-
f"kwargs[{k}]": v for k, v in kwargs.items()
|
36
|
-
}
|
37
|
-
return yield_mapping_repr(
|
38
|
-
_max_width=_max_width,
|
39
|
-
_indent_size=_indent_size,
|
40
|
-
_max_length=_max_length,
|
41
|
-
_max_string=_max_string,
|
42
|
-
_max_depth=_max_depth,
|
43
|
-
_expand_all=_expand_all,
|
44
|
-
**mapping,
|
45
|
-
)
|
46
|
-
|
47
|
-
|
48
|
-
##
|
49
|
-
|
50
|
-
|
51
|
-
def yield_mapping_repr(
|
52
|
-
_max_width: int = RICH_MAX_WIDTH,
|
53
|
-
_indent_size: int = RICH_INDENT_SIZE,
|
54
|
-
_max_length: int | None = RICH_MAX_LENGTH,
|
55
|
-
_max_string: int | None = RICH_MAX_STRING,
|
56
|
-
_max_depth: int | None = RICH_MAX_DEPTH,
|
57
|
-
_expand_all: bool = RICH_EXPAND_ALL, # noqa: FBT001
|
58
|
-
**kwargs: Any,
|
59
|
-
) -> Iterator[str]:
|
60
|
-
"""Pretty print of a set of keyword arguments."""
|
61
|
-
for k, v in kwargs.items():
|
62
|
-
v_repr = pretty_repr(
|
63
|
-
v,
|
64
|
-
max_width=_max_width,
|
65
|
-
indent_size=_indent_size,
|
66
|
-
max_length=_max_length,
|
67
|
-
max_string=_max_string,
|
68
|
-
max_depth=_max_depth,
|
69
|
-
expand_all=_expand_all,
|
70
|
-
)
|
71
|
-
yield f"{k} = {v_repr}"
|
72
|
-
|
73
|
-
|
74
|
-
__all__ = ["yield_call_args_repr", "yield_mapping_repr"]
|
File without changes
|
File without changes
|