dycw-utilities 0.133.1__py3-none-any.whl → 0.133.3__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.133.1
3
+ Version: 0.133.3
4
4
  Author-email: Derek Wan <d.wan@icloud.com>
5
5
  License-File: LICENSE
6
6
  Requires-Python: >=3.12
@@ -1,7 +1,7 @@
1
- utilities/__init__.py,sha256=Z40RN6IDVR495cIDu4FY4lG1K8hcbWIcPkM_PM_rASQ,60
1
+ utilities/__init__.py,sha256=31YVB_AJgxQM_m4eKVmVRXjVsNiMYmbkxB7m4Pc6W2Y,60
2
2
  utilities/aiolimiter.py,sha256=mD0wEiqMgwpty4XTbawFpnkkmJS6R4JRsVXFUaoitSU,628
3
3
  utilities/altair.py,sha256=HeZBVUocjkrTNwwKrClppsIqgNFF-ykv05HfZSoHYno,9104
4
- utilities/arq.py,sha256=YkwvWoL930hgeU9VP8iuP3RhMf0t8sm7O8qsD9TiyWo,4688
4
+ utilities/arq.py,sha256=objwVQZEmpX8XEtSdLB_Md_HY8VDEnT-_4Y_ujRy4NM,6498
5
5
  utilities/asyncio.py,sha256=USWMMrHqPVRr20vlIn_n5JLimyqa-5xLhuqDYWJed8A,37586
6
6
  utilities/atomicwrites.py,sha256=geFjn9Pwn-tTrtoGjDDxWli9NqbYfy3gGL6ZBctiqSo,5393
7
7
  utilities/atools.py,sha256=-bFGIrwYMFR7xl39j02DZMsO_u5x5_Ph7bRlBUFVYyw,1048
@@ -68,8 +68,8 @@ utilities/sentinel.py,sha256=3jIwgpMekWgDAxPDA_hXMP2St43cPhciKN3LWiZ7kv0,1248
68
68
  utilities/shelve.py,sha256=HZsMwK4tcIfg3sh0gApx4-yjQnrY4o3V3ZRimvRhoW0,738
69
69
  utilities/slack_sdk.py,sha256=SsRMJD2HuPUjAFg-2JxOQ9IhKViu4f66cN5kt-C2a7M,4245
70
70
  utilities/socket.py,sha256=K77vfREvzoVTrpYKo6MZakol0EYu2q1sWJnnZqL0So0,118
71
- utilities/sqlalchemy.py,sha256=2rApf8NNGdpT827ep19LFt2zCe_oHgF__0WYVk_svtw,38014
72
- utilities/sqlalchemy_polars.py,sha256=bDiKqHxOWu0Dj4ZDuGcVgR7ulm7sB90iVNINAKaeaKc,14290
71
+ utilities/sqlalchemy.py,sha256=A4_31D58RECTshpYQWRJ6Rr3s5gm8YeySp-5Z4R7lRQ,38065
72
+ utilities/sqlalchemy_polars.py,sha256=5TwuUPORZ1Nz3qbI6L6pzeThtEv8Ws4aQW8cm3MG-v0,14293
73
73
  utilities/statsmodels.py,sha256=koyiBHvpMcSiBfh99wFUfSggLNx7cuAw3rwyfAhoKpQ,3410
74
74
  utilities/streamlit.py,sha256=U9PJBaKP1IdSykKhPZhIzSPTZsmLsnwbEPZWzNhJPKk,2955
75
75
  utilities/string.py,sha256=XmU-s04qIV_tODnKl2pQiwmHaxzgOqRKU-RyzdrfvSE,620
@@ -89,7 +89,7 @@ utilities/warnings.py,sha256=un1LvHv70PU-LLv8RxPVmugTzDJkkGXRMZTE2-fTQHw,1771
89
89
  utilities/whenever.py,sha256=A-yoOqBqrcVD1yDINDsTFDw7dq9-zgUGn_f8CxVUQJs,23332
90
90
  utilities/zipfile.py,sha256=24lQc9ATcJxHXBPc_tBDiJk48pWyRrlxO2fIsFxU0A8,699
91
91
  utilities/zoneinfo.py,sha256=oEH-nL3t4h9uawyZqWDtNtDAl6M-CLpLYGI_nI6DulM,1971
92
- dycw_utilities-0.133.1.dist-info/METADATA,sha256=fZj3XXeQfb7y2obavSG6zSthc-oG_Zt-I33T3RVsHOE,1522
93
- dycw_utilities-0.133.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
94
- dycw_utilities-0.133.1.dist-info/licenses/LICENSE,sha256=gppZp16M6nSVpBbUBrNL6JuYfvKwZiKgV7XoKKsHzqo,1066
95
- dycw_utilities-0.133.1.dist-info/RECORD,,
92
+ dycw_utilities-0.133.3.dist-info/METADATA,sha256=6ApLAv1jFj_CI0Xt9tOqqzT847UVPMwvS9Y9BqA5z64,1522
93
+ dycw_utilities-0.133.3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
94
+ dycw_utilities-0.133.3.dist-info/licenses/LICENSE,sha256=gppZp16M6nSVpBbUBrNL6JuYfvKwZiKgV7XoKKsHzqo,1066
95
+ dycw_utilities-0.133.3.dist-info/RECORD,,
utilities/__init__.py CHANGED
@@ -1,3 +1,3 @@
1
1
  from __future__ import annotations
2
2
 
3
- __version__ = "0.133.1"
3
+ __version__ = "0.133.3"
utilities/arq.py CHANGED
@@ -3,18 +3,21 @@ from __future__ import annotations
3
3
  from dataclasses import dataclass
4
4
  from functools import wraps
5
5
  from itertools import chain
6
- from typing import TYPE_CHECKING, Any, ParamSpec, TypeVar, cast, override
6
+ from typing import TYPE_CHECKING, Any, ParamSpec, Self, TypeVar, cast, override
7
7
 
8
8
  from arq.constants import default_queue_name, expires_extra_ms
9
9
  from arq.cron import cron
10
10
 
11
+ from utilities.dataclasses import replace_non_sentinel
12
+ from utilities.sentinel import Sentinel, sentinel
13
+
11
14
  if TYPE_CHECKING:
12
15
  from collections.abc import Callable, Iterable, Sequence
13
- from datetime import timezone
16
+ from datetime import datetime, timedelta, timezone
14
17
 
15
18
  from arq.connections import ArqRedis, RedisSettings
16
19
  from arq.cron import CronJob
17
- from arq.jobs import Deserializer, Serializer
20
+ from arq.jobs import Deserializer, Job, Serializer
18
21
  from arq.typing import (
19
22
  OptionType,
20
23
  SecondsTimedelta,
@@ -26,6 +29,7 @@ if TYPE_CHECKING:
26
29
 
27
30
  from utilities.types import CallableCoroutine1, Coroutine1, StrMapping
28
31
 
32
+
29
33
  _P = ParamSpec("_P")
30
34
  _T = TypeVar("_T")
31
35
 
@@ -95,6 +99,64 @@ def _lift_cron(
95
99
  ##
96
100
 
97
101
 
102
+ @dataclass(kw_only=True, slots=True)
103
+ class _JobEnqueuer:
104
+ """Enqueuer of jobs."""
105
+
106
+ job_id: str | None = None
107
+ queue_name: str | None = None
108
+ defer_until: datetime | None = None
109
+ defer_by: int | float | timedelta | None = None
110
+ expires: int | float | timedelta | None = None
111
+ job_try: int | None = None
112
+
113
+ async def __call__(
114
+ self,
115
+ redis: ArqRedis,
116
+ function: Callable[_P, Coroutine1[_T]],
117
+ *args: _P.args,
118
+ **kwargs: _P.kwargs,
119
+ ) -> Job | None:
120
+ return await redis.enqueue_job( # skipif-ci-and-not-linux
121
+ function.__name__,
122
+ *args,
123
+ _job_id=self.job_id,
124
+ _queue_name=self.queue_name,
125
+ _defer_until=self.defer_until,
126
+ _defer_by=self.defer_by,
127
+ _expires=self.expires,
128
+ _job_try=self.job_try,
129
+ **kwargs,
130
+ )
131
+
132
+ def settings(
133
+ self,
134
+ *,
135
+ job_id: str | None | Sentinel = sentinel,
136
+ queue_name: str | None | Sentinel = sentinel,
137
+ defer_until: datetime | None | Sentinel = sentinel,
138
+ defer_by: float | timedelta | None | Sentinel = sentinel,
139
+ expires: float | timedelta | None | Sentinel = sentinel,
140
+ job_try: int | None | Sentinel = sentinel,
141
+ ) -> Self:
142
+ """Replace elements of the enqueuer."""
143
+ return replace_non_sentinel( # skipif-ci-and-not-linux
144
+ self,
145
+ job_id=job_id,
146
+ queue_name=queue_name,
147
+ defer_until=defer_until,
148
+ defer_by=defer_by,
149
+ expires=expires,
150
+ job_try=job_try,
151
+ )
152
+
153
+
154
+ job_enqueuer = _JobEnqueuer()
155
+
156
+
157
+ ##
158
+
159
+
98
160
  class _WorkerMeta(type):
99
161
  @override
100
162
  def __new__(
@@ -158,4 +220,4 @@ class Worker(metaclass=_WorkerMeta):
158
220
  log_results: bool = True
159
221
 
160
222
 
161
- __all__ = ["Worker", "cron"]
223
+ __all__ = ["Worker", "cron", "job_enqueuer"]
utilities/sqlalchemy.py CHANGED
@@ -298,11 +298,13 @@ def get_chunk_size(
298
298
  /,
299
299
  *,
300
300
  chunk_size_frac: float = CHUNK_SIZE_FRAC,
301
- scaling: float = 1.0,
301
+ max_length: int = 1,
302
302
  ) -> int:
303
303
  """Get the maximum chunk size for an engine."""
304
304
  max_params = _get_dialect_max_params(engine_or_conn)
305
- return max(floor(chunk_size_frac * max_params / scaling), 1)
305
+ scaling = max(max_length, 1)
306
+ size = floor(chunk_size_frac * max_params / scaling)
307
+ return max(size, 1)
306
308
 
307
309
 
308
310
  ##
@@ -1098,7 +1100,7 @@ def _prepare_insert_or_upsert_items(
1098
1100
  }
1099
1101
  max_length = max(lengths, default=1)
1100
1102
  chunk_size = get_chunk_size(
1101
- engine, chunk_size_frac=chunk_size_frac, scaling=max_length
1103
+ engine, chunk_size_frac=chunk_size_frac, max_length=max_length
1102
1104
  )
1103
1105
 
1104
1106
  def yield_pairs() -> Iterator[tuple[Insert, None]]:
@@ -433,7 +433,7 @@ def _select_to_dataframe_yield_selects_with_in_clauses(
433
433
  in_col, in_values = in_clauses
434
434
  if in_clauses_chunk_size is None:
435
435
  chunk_size = get_chunk_size(
436
- engine, chunk_size_frac=chunk_size_frac, scaling=max_length
436
+ engine, chunk_size_frac=chunk_size_frac, max_length=max_length
437
437
  )
438
438
  else:
439
439
  chunk_size = in_clauses_chunk_size