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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dycw-utilities
3
- Version: 0.126.10
3
+ Version: 0.126.12
4
4
  Author-email: Derek Wan <d.wan@icloud.com>
5
5
  License-File: LICENSE
6
6
  Requires-Python: >=3.12
@@ -1,4 +1,4 @@
1
- utilities/__init__.py,sha256=_LTfJC5B-XkbCDy-opJNk2Pu2qwhA3B84Baq2rX5bbA,61
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=XywncvQak9AYgdeN2M3vDJM9MEJsIFSfOiWVCKZVGjY,32697
65
- utilities/reprlib.py,sha256=Re9bk3n-kC__9DxQmRlevqFA86pE6TtVfWjUgpbVOv0,1849
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=KraI3PGrIs8ZpTQi0rZzBMjlcPbgWNipXlLySeu4aiY,36765
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=p9WATV-e4_5AW6SvyRBiU-MY8XnEFcKgrFNUoFzalXI,27521
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.10.dist-info/METADATA,sha256=3hajeWxg9om0FI0yM_fkaoFNZFG_j4slCdaV-NRNswU,12804
95
- dycw_utilities-0.126.10.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
96
- dycw_utilities-0.126.10.dist-info/licenses/LICENSE,sha256=gppZp16M6nSVpBbUBrNL6JuYfvKwZiKgV7XoKKsHzqo,1066
97
- dycw_utilities-0.126.10.dist-info/RECORD,,
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
@@ -1,3 +1,3 @@
1
1
  from __future__ import annotations
2
2
 
3
- __version__ = "0.126.10"
3
+ __version__ = "0.126.12"
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 EnhancedQueue, InfiniteQueueLooper, Looper, timeout_dur
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 = SECOND
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 typing import Any
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 InfiniteQueueLooper, Looper, timeout_dur
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"]