dycw-utilities 0.126.10__py3-none-any.whl → 0.126.11__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.11.dist-info}/METADATA +1 -1
- {dycw_utilities-0.126.10.dist-info → dycw_utilities-0.126.11.dist-info}/RECORD +7 -7
- utilities/__init__.py +1 -1
- utilities/redis.py +115 -5
- utilities/sqlalchemy.py +65 -1
- {dycw_utilities-0.126.10.dist-info → dycw_utilities-0.126.11.dist-info}/WHEEL +0 -0
- {dycw_utilities-0.126.10.dist-info → dycw_utilities-0.126.11.dist-info}/licenses/LICENSE +0 -0
@@ -1,4 +1,4 @@
|
|
1
|
-
utilities/__init__.py,sha256=
|
1
|
+
utilities/__init__.py,sha256=zZdDjXYw0iXgNb3iikpaOv2GNjXKtYX9dLFyhvGm1Bs,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,7 +61,7 @@ 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=
|
64
|
+
utilities/redis.py,sha256=pMKJjNI5e0lG-FZh2_idMBBmfgNr53KIGjBquZQOLZc,37556
|
65
65
|
utilities/reprlib.py,sha256=Re9bk3n-kC__9DxQmRlevqFA86pE6TtVfWjUgpbVOv0,1849
|
66
66
|
utilities/rich.py,sha256=t50MwwVBsoOLxzmeVFSVpjno4OW6Ufum32skXbV8-Bs,1911
|
67
67
|
utilities/scipy.py,sha256=X6ROnHwiUhAmPhM0jkfEh0-Fd9iRvwiqtCQMOLmOQF8,945
|
@@ -69,7 +69,7 @@ utilities/sentinel.py,sha256=3jIwgpMekWgDAxPDA_hXMP2St43cPhciKN3LWiZ7kv0,1248
|
|
69
69
|
utilities/shelve.py,sha256=HZsMwK4tcIfg3sh0gApx4-yjQnrY4o3V3ZRimvRhoW0,738
|
70
70
|
utilities/slack_sdk.py,sha256=h2DiVkcFyYcT5zzZOAo6CSith5BBlHUbXeOJSL1neK8,5948
|
71
71
|
utilities/socket.py,sha256=K77vfREvzoVTrpYKo6MZakol0EYu2q1sWJnnZqL0So0,118
|
72
|
-
utilities/sqlalchemy.py,sha256=
|
72
|
+
utilities/sqlalchemy.py,sha256=rHixzaYl_QHTR1dAhLj15ntiE5kwZWY4MKIr97crDts,39602
|
73
73
|
utilities/sqlalchemy_polars.py,sha256=s7hQNep2O5DTgIRXyN_JRQma7a4DAtNd25tshaZW8iw,15490
|
74
74
|
utilities/statsmodels.py,sha256=koyiBHvpMcSiBfh99wFUfSggLNx7cuAw3rwyfAhoKpQ,3410
|
75
75
|
utilities/streamlit.py,sha256=U9PJBaKP1IdSykKhPZhIzSPTZsmLsnwbEPZWzNhJPKk,2955
|
@@ -91,7 +91,7 @@ utilities/warnings.py,sha256=un1LvHv70PU-LLv8RxPVmugTzDJkkGXRMZTE2-fTQHw,1771
|
|
91
91
|
utilities/whenever.py,sha256=jS31ZAY5OMxFxLja_Yo5Fidi87Pd-GoVZ7Vi_teqVDA,16743
|
92
92
|
utilities/zipfile.py,sha256=24lQc9ATcJxHXBPc_tBDiJk48pWyRrlxO2fIsFxU0A8,699
|
93
93
|
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.
|
94
|
+
dycw_utilities-0.126.11.dist-info/METADATA,sha256=BpSldlx63eNjZ98CKmHpEi6Ee2Zm5HqWnYZrKbBOICI,12804
|
95
|
+
dycw_utilities-0.126.11.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
96
|
+
dycw_utilities-0.126.11.dist-info/licenses/LICENSE,sha256=gppZp16M6nSVpBbUBrNL6JuYfvKwZiKgV7XoKKsHzqo,1066
|
97
|
+
dycw_utilities-0.126.11.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/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",
|
File without changes
|
File without changes
|