dycw-utilities 0.121.0__py3-none-any.whl → 0.122.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.121.0.dist-info → dycw_utilities-0.122.0.dist-info}/METADATA +37 -37
- {dycw_utilities-0.121.0.dist-info → dycw_utilities-0.122.0.dist-info}/RECORD +10 -10
- utilities/__init__.py +1 -1
- utilities/asyncio.py +132 -29
- utilities/fastapi.py +4 -0
- utilities/polars.py +5 -5
- utilities/redis.py +1 -1
- utilities/sqlalchemy.py +1 -1
- {dycw_utilities-0.121.0.dist-info → dycw_utilities-0.122.0.dist-info}/WHEEL +0 -0
- {dycw_utilities-0.121.0.dist-info → dycw_utilities-0.122.0.dist-info}/licenses/LICENSE +0 -0
@@ -1,12 +1,12 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: dycw-utilities
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.122.0
|
4
4
|
Author-email: Derek Wan <d.wan@icloud.com>
|
5
5
|
License-File: LICENSE
|
6
6
|
Requires-Python: >=3.12
|
7
7
|
Requires-Dist: typing-extensions<4.14,>=4.13.1
|
8
8
|
Provides-Extra: test
|
9
|
-
Requires-Dist: hypothesis<6.132,>=6.131.
|
9
|
+
Requires-Dist: hypothesis<6.132,>=6.131.21; extra == 'test'
|
10
10
|
Requires-Dist: pytest-asyncio<0.27,>=0.26.0; extra == 'test'
|
11
11
|
Requires-Dist: pytest-cov<6.2,>=6.1.1; extra == 'test'
|
12
12
|
Requires-Dist: pytest-instafail<0.6,>=0.5.0; extra == 'test'
|
@@ -24,9 +24,9 @@ Provides-Extra: zzz-test-altair
|
|
24
24
|
Requires-Dist: altair<5.6,>=5.5.0; extra == 'zzz-test-altair'
|
25
25
|
Requires-Dist: atomicwrites<1.5,>=1.4.1; extra == 'zzz-test-altair'
|
26
26
|
Requires-Dist: img2pdf<0.7,>=0.6.0; extra == 'zzz-test-altair'
|
27
|
-
Requires-Dist: polars-lts-cpu<1.
|
27
|
+
Requires-Dist: polars-lts-cpu<1.31,>=1.30.0; extra == 'zzz-test-altair'
|
28
28
|
Requires-Dist: vl-convert-python<1.8,>=1.7.0; extra == 'zzz-test-altair'
|
29
|
-
Requires-Dist: whenever<0.9,>=0.8.
|
29
|
+
Requires-Dist: whenever<0.9,>=0.8.2; extra == 'zzz-test-altair'
|
30
30
|
Provides-Extra: zzz-test-astor
|
31
31
|
Requires-Dist: astor<0.9,>=0.8.1; extra == 'zzz-test-astor'
|
32
32
|
Provides-Extra: zzz-test-asyncio
|
@@ -37,9 +37,9 @@ Requires-Dist: atools<0.15,>=0.14.2; extra == 'zzz-test-atools'
|
|
37
37
|
Provides-Extra: zzz-test-cachetools
|
38
38
|
Requires-Dist: cachetools<5.6,>=5.5.2; extra == 'zzz-test-cachetools'
|
39
39
|
Provides-Extra: zzz-test-click
|
40
|
-
Requires-Dist: click<8.3,>=8.2.
|
40
|
+
Requires-Dist: click<8.3,>=8.2.1; extra == 'zzz-test-click'
|
41
41
|
Requires-Dist: sqlalchemy<2.1,>=2.0.41; extra == 'zzz-test-click'
|
42
|
-
Requires-Dist: whenever<0.9,>=0.8.
|
42
|
+
Requires-Dist: whenever<0.9,>=0.8.2; extra == 'zzz-test-click'
|
43
43
|
Provides-Extra: zzz-test-contextlib
|
44
44
|
Provides-Extra: zzz-test-contextvars
|
45
45
|
Provides-Extra: zzz-test-cryptography
|
@@ -48,11 +48,11 @@ Provides-Extra: zzz-test-cvxpy
|
|
48
48
|
Requires-Dist: cvxpy<1.7,>=1.6.5; extra == 'zzz-test-cvxpy'
|
49
49
|
Provides-Extra: zzz-test-dataclasses
|
50
50
|
Requires-Dist: orjson<3.11,>=3.10.15; extra == 'zzz-test-dataclasses'
|
51
|
-
Requires-Dist: polars-lts-cpu<1.
|
52
|
-
Requires-Dist: whenever<0.9,>=0.8.
|
51
|
+
Requires-Dist: polars-lts-cpu<1.31,>=1.30.0; extra == 'zzz-test-dataclasses'
|
52
|
+
Requires-Dist: whenever<0.9,>=0.8.2; extra == 'zzz-test-dataclasses'
|
53
53
|
Provides-Extra: zzz-test-datetime
|
54
54
|
Requires-Dist: tzlocal<5.4,>=5.3.1; extra == 'zzz-test-datetime'
|
55
|
-
Requires-Dist: whenever<0.9,>=0.8.
|
55
|
+
Requires-Dist: whenever<0.9,>=0.8.2; extra == 'zzz-test-datetime'
|
56
56
|
Provides-Extra: zzz-test-enum
|
57
57
|
Provides-Extra: zzz-test-errors
|
58
58
|
Provides-Extra: zzz-test-eventkit
|
@@ -70,17 +70,17 @@ Provides-Extra: zzz-test-getpass
|
|
70
70
|
Provides-Extra: zzz-test-git
|
71
71
|
Provides-Extra: zzz-test-hashlib
|
72
72
|
Requires-Dist: orjson<3.11,>=3.10.15; extra == 'zzz-test-hashlib'
|
73
|
-
Requires-Dist: polars-lts-cpu<1.
|
74
|
-
Requires-Dist: whenever<0.9,>=0.8.
|
73
|
+
Requires-Dist: polars-lts-cpu<1.31,>=1.30.0; extra == 'zzz-test-hashlib'
|
74
|
+
Requires-Dist: whenever<0.9,>=0.8.2; extra == 'zzz-test-hashlib'
|
75
75
|
Provides-Extra: zzz-test-http
|
76
76
|
Requires-Dist: atomicwrites<1.5,>=1.4.1; extra == 'zzz-test-http'
|
77
77
|
Requires-Dist: orjson<3.11,>=3.10.18; extra == 'zzz-test-http'
|
78
|
-
Requires-Dist: whenever<0.9,>=0.8.
|
78
|
+
Requires-Dist: whenever<0.9,>=0.8.2; extra == 'zzz-test-http'
|
79
79
|
Provides-Extra: zzz-test-hypothesis
|
80
80
|
Requires-Dist: aiosqlite<0.22,>=0.21.0; extra == 'zzz-test-hypothesis'
|
81
81
|
Requires-Dist: asyncpg<0.31,>=0.30.0; extra == 'zzz-test-hypothesis'
|
82
82
|
Requires-Dist: greenlet<3.3,>=3.2.0; extra == 'zzz-test-hypothesis'
|
83
|
-
Requires-Dist: hypothesis<6.132,>=6.131.
|
83
|
+
Requires-Dist: hypothesis<6.132,>=6.131.21; extra == 'zzz-test-hypothesis'
|
84
84
|
Requires-Dist: luigi<3.7,>=3.6.0; extra == 'zzz-test-hypothesis'
|
85
85
|
Requires-Dist: numpy<2.3,>=2.2.6; extra == 'zzz-test-hypothesis'
|
86
86
|
Requires-Dist: pathvalidate<3.3,>=3.2.3; extra == 'zzz-test-hypothesis'
|
@@ -88,16 +88,16 @@ Requires-Dist: redis<6.2,>=6.1.0; extra == 'zzz-test-hypothesis'
|
|
88
88
|
Requires-Dist: sqlalchemy<2.1,>=2.0.41; extra == 'zzz-test-hypothesis'
|
89
89
|
Requires-Dist: tenacity<9.0,>=8.5.0; extra == 'zzz-test-hypothesis'
|
90
90
|
Requires-Dist: tzlocal<5.4,>=5.3.1; extra == 'zzz-test-hypothesis'
|
91
|
-
Requires-Dist: whenever<0.9,>=0.8.
|
91
|
+
Requires-Dist: whenever<0.9,>=0.8.2; extra == 'zzz-test-hypothesis'
|
92
92
|
Provides-Extra: zzz-test-ipython
|
93
93
|
Requires-Dist: ipython<9.1,>=9.0.1; extra == 'zzz-test-ipython'
|
94
94
|
Provides-Extra: zzz-test-iterables
|
95
|
-
Requires-Dist: polars-lts-cpu<1.
|
96
|
-
Requires-Dist: whenever<0.9,>=0.8.
|
95
|
+
Requires-Dist: polars-lts-cpu<1.31,>=1.30.0; extra == 'zzz-test-iterables'
|
96
|
+
Requires-Dist: whenever<0.9,>=0.8.2; extra == 'zzz-test-iterables'
|
97
97
|
Provides-Extra: zzz-test-jupyter
|
98
98
|
Requires-Dist: jupyterlab<4.3,>=4.2.0; extra == 'zzz-test-jupyter'
|
99
99
|
Requires-Dist: pandas<2.3,>=2.2.2; extra == 'zzz-test-jupyter'
|
100
|
-
Requires-Dist: polars-lts-cpu<1.
|
100
|
+
Requires-Dist: polars-lts-cpu<1.31,>=1.30.0; extra == 'zzz-test-jupyter'
|
101
101
|
Provides-Extra: zzz-test-logging
|
102
102
|
Requires-Dist: atomicwrites<1.5,>=1.4.1; extra == 'zzz-test-logging'
|
103
103
|
Requires-Dist: coloredlogs<15.1,>=15.0.1; extra == 'zzz-test-logging'
|
@@ -105,12 +105,12 @@ Requires-Dist: concurrent-log-handler<0.10,>=0.9.26; extra == 'zzz-test-logging'
|
|
105
105
|
Requires-Dist: rich<14.1,>=14.0.0; extra == 'zzz-test-logging'
|
106
106
|
Requires-Dist: tomlkit<0.14,>=0.13.2; extra == 'zzz-test-logging'
|
107
107
|
Requires-Dist: tzlocal<5.4,>=5.3.1; extra == 'zzz-test-logging'
|
108
|
-
Requires-Dist: whenever<0.9,>=0.8.
|
108
|
+
Requires-Dist: whenever<0.9,>=0.8.2; extra == 'zzz-test-logging'
|
109
109
|
Provides-Extra: zzz-test-loguru
|
110
110
|
Requires-Dist: loguru<0.8,>=0.7.3; extra == 'zzz-test-loguru'
|
111
111
|
Provides-Extra: zzz-test-luigi
|
112
112
|
Requires-Dist: luigi<3.7,>=3.6.0; extra == 'zzz-test-luigi'
|
113
|
-
Requires-Dist: whenever<0.9,>=0.8.
|
113
|
+
Requires-Dist: whenever<0.9,>=0.8.2; extra == 'zzz-test-luigi'
|
114
114
|
Provides-Extra: zzz-test-math
|
115
115
|
Requires-Dist: numpy<2.3,>=2.2.6; extra == 'zzz-test-math'
|
116
116
|
Provides-Extra: zzz-test-memory-profiler
|
@@ -121,24 +121,24 @@ Requires-Dist: more-itertools<10.8,>=10.7.0; extra == 'zzz-test-more-itertools'
|
|
121
121
|
Provides-Extra: zzz-test-numpy
|
122
122
|
Requires-Dist: numpy<2.3,>=2.2.6; extra == 'zzz-test-numpy'
|
123
123
|
Provides-Extra: zzz-test-operator
|
124
|
-
Requires-Dist: polars-lts-cpu<1.
|
125
|
-
Requires-Dist: whenever<0.9,>=0.8.
|
124
|
+
Requires-Dist: polars-lts-cpu<1.31,>=1.30.0; extra == 'zzz-test-operator'
|
125
|
+
Requires-Dist: whenever<0.9,>=0.8.2; extra == 'zzz-test-operator'
|
126
126
|
Provides-Extra: zzz-test-optuna
|
127
127
|
Requires-Dist: optuna<4.4,>=4.3.0; extra == 'zzz-test-optuna'
|
128
128
|
Provides-Extra: zzz-test-orjson
|
129
129
|
Requires-Dist: orjson<3.11,>=3.10.15; extra == 'zzz-test-orjson'
|
130
|
-
Requires-Dist: polars-lts-cpu<1.
|
130
|
+
Requires-Dist: polars-lts-cpu<1.31,>=1.30.0; extra == 'zzz-test-orjson'
|
131
131
|
Requires-Dist: rich<14.1,>=14.0.0; extra == 'zzz-test-orjson'
|
132
132
|
Requires-Dist: tzlocal<5.4,>=5.3.1; extra == 'zzz-test-orjson'
|
133
|
-
Requires-Dist: whenever<0.9,>=0.8.
|
133
|
+
Requires-Dist: whenever<0.9,>=0.8.2; extra == 'zzz-test-orjson'
|
134
134
|
Provides-Extra: zzz-test-os
|
135
135
|
Provides-Extra: zzz-test-pathlib
|
136
136
|
Provides-Extra: zzz-test-pickle
|
137
137
|
Requires-Dist: atomicwrites<1.5,>=1.4.1; extra == 'zzz-test-pickle'
|
138
138
|
Provides-Extra: zzz-test-platform
|
139
139
|
Provides-Extra: zzz-test-polars
|
140
|
-
Requires-Dist: polars-lts-cpu<1.
|
141
|
-
Requires-Dist: whenever<0.9,>=0.8.
|
140
|
+
Requires-Dist: polars-lts-cpu<1.31,>=1.30.0; extra == 'zzz-test-polars'
|
141
|
+
Requires-Dist: whenever<0.9,>=0.8.2; extra == 'zzz-test-polars'
|
142
142
|
Provides-Extra: zzz-test-pqdm
|
143
143
|
Requires-Dist: pqdm<0.3,>=0.2.0; extra == 'zzz-test-pqdm'
|
144
144
|
Provides-Extra: zzz-test-pydantic
|
@@ -153,22 +153,22 @@ Requires-Dist: pyrsistent<0.21,>=0.20.0; extra == 'zzz-test-pyrsistent'
|
|
153
153
|
Provides-Extra: zzz-test-pytest
|
154
154
|
Requires-Dist: atomicwrites<1.5,>=1.4.1; extra == 'zzz-test-pytest'
|
155
155
|
Requires-Dist: orjson<3.11,>=3.10.18; extra == 'zzz-test-pytest'
|
156
|
-
Requires-Dist: whenever<0.9,>=0.8.
|
156
|
+
Requires-Dist: whenever<0.9,>=0.8.2; extra == 'zzz-test-pytest'
|
157
157
|
Provides-Extra: zzz-test-pytest-regressions
|
158
158
|
Requires-Dist: pytest-regressions<2.8,>=2.7.0; extra == 'zzz-test-pytest-regressions'
|
159
159
|
Provides-Extra: zzz-test-python-dotenv
|
160
160
|
Requires-Dist: python-dotenv<1.2,>=1.1.0; extra == 'zzz-test-python-dotenv'
|
161
|
-
Requires-Dist: whenever<0.9,>=0.8.
|
161
|
+
Requires-Dist: whenever<0.9,>=0.8.2; extra == 'zzz-test-python-dotenv'
|
162
162
|
Provides-Extra: zzz-test-random
|
163
163
|
Provides-Extra: zzz-test-re
|
164
164
|
Provides-Extra: zzz-test-redis
|
165
165
|
Requires-Dist: orjson<3.11,>=3.10.15; extra == 'zzz-test-redis'
|
166
|
-
Requires-Dist: polars-lts-cpu<1.
|
166
|
+
Requires-Dist: polars-lts-cpu<1.31,>=1.30.0; extra == 'zzz-test-redis'
|
167
167
|
Requires-Dist: redis<6.2,>=6.1.0; extra == 'zzz-test-redis'
|
168
168
|
Requires-Dist: rich<14.1,>=14.0.0; extra == 'zzz-test-redis'
|
169
169
|
Requires-Dist: tenacity<9.0,>=8.5.0; extra == 'zzz-test-redis'
|
170
170
|
Requires-Dist: tzlocal<5.4,>=5.3.1; extra == 'zzz-test-redis'
|
171
|
-
Requires-Dist: whenever<0.9,>=0.8.
|
171
|
+
Requires-Dist: whenever<0.9,>=0.8.2; extra == 'zzz-test-redis'
|
172
172
|
Provides-Extra: zzz-test-rich
|
173
173
|
Requires-Dist: rich<14.1,>=14.0.0; extra == 'zzz-test-rich'
|
174
174
|
Provides-Extra: zzz-test-scipy
|
@@ -191,10 +191,10 @@ Requires-Dist: aiosqlite<0.22,>=0.21.0; extra == 'zzz-test-sqlalchemy-polars'
|
|
191
191
|
Requires-Dist: asyncpg<0.31,>=0.30.0; extra == 'zzz-test-sqlalchemy-polars'
|
192
192
|
Requires-Dist: greenlet<3.3,>=3.2.0; extra == 'zzz-test-sqlalchemy-polars'
|
193
193
|
Requires-Dist: nest-asyncio<1.7,>=1.6.0; extra == 'zzz-test-sqlalchemy-polars'
|
194
|
-
Requires-Dist: polars-lts-cpu<1.
|
194
|
+
Requires-Dist: polars-lts-cpu<1.31,>=1.30.0; extra == 'zzz-test-sqlalchemy-polars'
|
195
195
|
Requires-Dist: sqlalchemy<2.1,>=2.0.41; extra == 'zzz-test-sqlalchemy-polars'
|
196
196
|
Requires-Dist: tenacity<9.0,>=8.5.0; extra == 'zzz-test-sqlalchemy-polars'
|
197
|
-
Requires-Dist: whenever<0.9,>=0.8.
|
197
|
+
Requires-Dist: whenever<0.9,>=0.8.2; extra == 'zzz-test-sqlalchemy-polars'
|
198
198
|
Provides-Extra: zzz-test-streamlit
|
199
199
|
Requires-Dist: streamlit<1.46,>=1.45.0; extra == 'zzz-test-streamlit'
|
200
200
|
Provides-Extra: zzz-test-sys
|
@@ -202,7 +202,7 @@ Requires-Dist: atomicwrites<1.5,>=1.4.1; extra == 'zzz-test-sys'
|
|
202
202
|
Requires-Dist: rich<14.1,>=14.0.0; extra == 'zzz-test-sys'
|
203
203
|
Requires-Dist: tomlkit<0.14,>=0.13.2; extra == 'zzz-test-sys'
|
204
204
|
Requires-Dist: tzlocal<5.4,>=5.3.1; extra == 'zzz-test-sys'
|
205
|
-
Requires-Dist: whenever<0.9,>=0.8.
|
205
|
+
Requires-Dist: whenever<0.9,>=0.8.2; extra == 'zzz-test-sys'
|
206
206
|
Provides-Extra: zzz-test-tempfile
|
207
207
|
Provides-Extra: zzz-test-tenacity
|
208
208
|
Requires-Dist: tenacity<9.0,>=8.5.0; extra == 'zzz-test-tenacity'
|
@@ -213,11 +213,11 @@ Provides-Extra: zzz-test-traceback
|
|
213
213
|
Requires-Dist: rich<14.1,>=14.0.0; extra == 'zzz-test-traceback'
|
214
214
|
Requires-Dist: tomlkit<0.14,>=0.13.2; extra == 'zzz-test-traceback'
|
215
215
|
Requires-Dist: tzlocal<5.4,>=5.3.1; extra == 'zzz-test-traceback'
|
216
|
-
Requires-Dist: whenever<0.9,>=0.8.
|
216
|
+
Requires-Dist: whenever<0.9,>=0.8.2; extra == 'zzz-test-traceback'
|
217
217
|
Provides-Extra: zzz-test-types
|
218
218
|
Provides-Extra: zzz-test-typing
|
219
|
-
Requires-Dist: polars-lts-cpu<1.
|
220
|
-
Requires-Dist: whenever<0.9,>=0.8.
|
219
|
+
Requires-Dist: polars-lts-cpu<1.31,>=1.30.0; extra == 'zzz-test-typing'
|
220
|
+
Requires-Dist: whenever<0.9,>=0.8.2; extra == 'zzz-test-typing'
|
221
221
|
Provides-Extra: zzz-test-tzlocal
|
222
222
|
Requires-Dist: tzlocal<5.4,>=5.3.1; extra == 'zzz-test-tzlocal'
|
223
223
|
Provides-Extra: zzz-test-uuid
|
@@ -225,11 +225,11 @@ Provides-Extra: zzz-test-version
|
|
225
225
|
Requires-Dist: tomlkit<0.14,>=0.13.2; extra == 'zzz-test-version'
|
226
226
|
Provides-Extra: zzz-test-warnings
|
227
227
|
Provides-Extra: zzz-test-whenever
|
228
|
-
Requires-Dist: whenever<0.9,>=0.8.
|
228
|
+
Requires-Dist: whenever<0.9,>=0.8.2; extra == 'zzz-test-whenever'
|
229
229
|
Provides-Extra: zzz-test-zipfile
|
230
230
|
Provides-Extra: zzz-test-zoneinfo
|
231
231
|
Requires-Dist: tzdata<2025.3,>=2025.2; extra == 'zzz-test-zoneinfo'
|
232
|
-
Requires-Dist: whenever<0.9,>=0.8.
|
232
|
+
Requires-Dist: whenever<0.9,>=0.8.2; extra == 'zzz-test-zoneinfo'
|
233
233
|
Description-Content-Type: text/markdown
|
234
234
|
|
235
235
|
[](https://badge.fury.io/py/dycw-utilities)
|
@@ -1,7 +1,7 @@
|
|
1
|
-
utilities/__init__.py,sha256=
|
1
|
+
utilities/__init__.py,sha256=V19RNamTpOs4KxZ_wh7w8SsT-d-C24iIQHK07Pu3opA,60
|
2
2
|
utilities/altair.py,sha256=Gpja-flOo-Db0PIPJLJsgzAlXWoKUjPU1qY-DQ829ek,9156
|
3
3
|
utilities/astor.py,sha256=xuDUkjq0-b6fhtwjhbnebzbqQZAjMSHR1IIS5uOodVg,777
|
4
|
-
utilities/asyncio.py,sha256=
|
4
|
+
utilities/asyncio.py,sha256=sVCGCGl5vGo1MztLcd46DiuWBR6XQW1CsGDyDdaevYg,22766
|
5
5
|
utilities/atomicwrites.py,sha256=geFjn9Pwn-tTrtoGjDDxWli9NqbYfy3gGL6ZBctiqSo,5393
|
6
6
|
utilities/atools.py,sha256=IYMuFSFGSKyuQmqD6v5IUtDlz8PPw0Sr87Cub_gRU3M,1168
|
7
7
|
utilities/cachetools.py,sha256=C1zqOg7BYz0IfQFK8e3qaDDgEZxDpo47F15RTfJM37Q,2910
|
@@ -16,7 +16,7 @@ utilities/datetime.py,sha256=uYoaOi_C1YtNXGfTN9xlTrW62Re2b1_4Skuv14_MeYQ,38985
|
|
16
16
|
utilities/enum.py,sha256=HoRwVCWzsnH0vpO9ZEcAAIZLMv0Sn2vJxxA4sYMQgDs,5793
|
17
17
|
utilities/errors.py,sha256=gxsaa7eq7jbYl41Of40-ivjXqJB5gt4QAcJ0smZZMJE,829
|
18
18
|
utilities/eventkit.py,sha256=6M5Xu1SzN-juk9PqBHwy5dS-ta7T0qA6SMpDsakOJ0E,13039
|
19
|
-
utilities/fastapi.py,sha256=
|
19
|
+
utilities/fastapi.py,sha256=LG1-Q8RDi7wsyVN6v74qptPYX8WGXPkFOQFniMvtzjc,2439
|
20
20
|
utilities/fpdf2.py,sha256=y1NGXR5chWqLXWpewGV3hlRGMr_5yV1lVRkPBhPEgJI,1843
|
21
21
|
utilities/functions.py,sha256=jgt592voaHNtX56qX0SRvFveVCRmSIxCZmqvpLZCnY8,27305
|
22
22
|
utilities/functools.py,sha256=WrpHt7NLNWSUn9A1Q_ZIWlNaYZOEI4IFKyBG9HO3BC4,1643
|
@@ -47,7 +47,7 @@ utilities/pathlib.py,sha256=31WPMXdLIyXgYOMMl_HOI2wlo66MGSE-cgeelk-Lias,1410
|
|
47
47
|
utilities/period.py,sha256=o4wXYEXVlFomop4-Ra4L0yRP4i99NZFjIe_fa7NdZck,11024
|
48
48
|
utilities/pickle.py,sha256=Bhvd7cZl-zQKQDFjUerqGuSKlHvnW1K2QXeU5UZibtg,657
|
49
49
|
utilities/platform.py,sha256=NU7ycTvAXAG-fdYmDXaM1m4EOml2cGiaYwaUzfzSqyU,1767
|
50
|
-
utilities/polars.py,sha256=
|
50
|
+
utilities/polars.py,sha256=tGO3r6S4lFtir6zbdIvZ_kvKBWIha4lnA1eEmV3EvNQ,63632
|
51
51
|
utilities/polars_ols.py,sha256=efhXf0gjrHUpQrvS6a7g8yJQJWf_ATKtJnqqF2inCOU,5680
|
52
52
|
utilities/pqdm.py,sha256=foRytQybmOQ05pjt5LF7ANyzrIa--4ScDE3T2wd31a4,3118
|
53
53
|
utilities/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
@@ -59,7 +59,7 @@ utilities/pytest_regressions.py,sha256=-SVT9647Dg6-JcdsiaDKXe3NdOmmrvGevLKWwGjxq
|
|
59
59
|
utilities/python_dotenv.py,sha256=iWcnpXbH7S6RoXHiLlGgyuH6udCupAcPd_gQ0eAenQ0,3190
|
60
60
|
utilities/random.py,sha256=lYdjgxB7GCfU_fwFVl5U-BIM_HV3q6_urL9byjrwDM8,4157
|
61
61
|
utilities/re.py,sha256=5J4d8VwIPFVrX2Eb8zfoxImDv7IwiN_U7mJ07wR2Wvs,3958
|
62
|
-
utilities/redis.py,sha256=
|
62
|
+
utilities/redis.py,sha256=8ELnXiISVHY1m9elJWhekhLXg6NQSaNIIPvZ_EaGw3s,26624
|
63
63
|
utilities/reprlib.py,sha256=Re9bk3n-kC__9DxQmRlevqFA86pE6TtVfWjUgpbVOv0,1849
|
64
64
|
utilities/rich.py,sha256=t50MwwVBsoOLxzmeVFSVpjno4OW6Ufum32skXbV8-Bs,1911
|
65
65
|
utilities/scipy.py,sha256=X6ROnHwiUhAmPhM0jkfEh0-Fd9iRvwiqtCQMOLmOQF8,945
|
@@ -67,7 +67,7 @@ utilities/sentinel.py,sha256=3jIwgpMekWgDAxPDA_hXMP2St43cPhciKN3LWiZ7kv0,1248
|
|
67
67
|
utilities/shelve.py,sha256=HZsMwK4tcIfg3sh0gApx4-yjQnrY4o3V3ZRimvRhoW0,738
|
68
68
|
utilities/slack_sdk.py,sha256=A2f7-DYOngRoUP6ZdLIaUQ6Lfzgru5Xp3U3k5JfEkQE,3301
|
69
69
|
utilities/socket.py,sha256=K77vfREvzoVTrpYKo6MZakol0EYu2q1sWJnnZqL0So0,118
|
70
|
-
utilities/sqlalchemy.py,sha256=
|
70
|
+
utilities/sqlalchemy.py,sha256=yCUCDhg0wFOCdEh6wwBD7Ma979OksLpz4arck1s653s,35447
|
71
71
|
utilities/sqlalchemy_polars.py,sha256=wjJpoUo-yO9E2ujpG_06vV5r2OdvBiQ4yvV6wKCa2Tk,15605
|
72
72
|
utilities/statsmodels.py,sha256=koyiBHvpMcSiBfh99wFUfSggLNx7cuAw3rwyfAhoKpQ,3410
|
73
73
|
utilities/streamlit.py,sha256=U9PJBaKP1IdSykKhPZhIzSPTZsmLsnwbEPZWzNhJPKk,2955
|
@@ -88,7 +88,7 @@ utilities/warnings.py,sha256=un1LvHv70PU-LLv8RxPVmugTzDJkkGXRMZTE2-fTQHw,1771
|
|
88
88
|
utilities/whenever.py,sha256=jS31ZAY5OMxFxLja_Yo5Fidi87Pd-GoVZ7Vi_teqVDA,16743
|
89
89
|
utilities/zipfile.py,sha256=24lQc9ATcJxHXBPc_tBDiJk48pWyRrlxO2fIsFxU0A8,699
|
90
90
|
utilities/zoneinfo.py,sha256=-5j7IQ9nb7gR43rdgA7ms05im-XuqhAk9EJnQBXxCoQ,1874
|
91
|
-
dycw_utilities-0.
|
92
|
-
dycw_utilities-0.
|
93
|
-
dycw_utilities-0.
|
94
|
-
dycw_utilities-0.
|
91
|
+
dycw_utilities-0.122.0.dist-info/METADATA,sha256=VUsd4omUw1y-str8uasKFbLZUMA2Sr3HpSaq8f8coh0,12943
|
92
|
+
dycw_utilities-0.122.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
93
|
+
dycw_utilities-0.122.0.dist-info/licenses/LICENSE,sha256=gppZp16M6nSVpBbUBrNL6JuYfvKwZiKgV7XoKKsHzqo,1066
|
94
|
+
dycw_utilities-0.122.0.dist-info/RECORD,,
|
utilities/__init__.py
CHANGED
utilities/asyncio.py
CHANGED
@@ -3,6 +3,7 @@ from __future__ import annotations
|
|
3
3
|
import datetime as dt
|
4
4
|
from abc import ABC, abstractmethod
|
5
5
|
from asyncio import (
|
6
|
+
CancelledError,
|
6
7
|
Event,
|
7
8
|
PriorityQueue,
|
8
9
|
Queue,
|
@@ -12,11 +13,17 @@ from asyncio import (
|
|
12
13
|
Task,
|
13
14
|
TaskGroup,
|
14
15
|
create_subprocess_shell,
|
16
|
+
create_task,
|
15
17
|
sleep,
|
16
18
|
timeout,
|
17
19
|
)
|
18
20
|
from collections.abc import Callable, Hashable, Iterable, Iterator, Mapping
|
19
|
-
from contextlib import
|
21
|
+
from contextlib import (
|
22
|
+
AsyncExitStack,
|
23
|
+
_AsyncGeneratorContextManager,
|
24
|
+
asynccontextmanager,
|
25
|
+
suppress,
|
26
|
+
)
|
20
27
|
from dataclasses import dataclass, field
|
21
28
|
from io import StringIO
|
22
29
|
from logging import getLogger
|
@@ -27,6 +34,7 @@ from typing import (
|
|
27
34
|
Any,
|
28
35
|
Generic,
|
29
36
|
NoReturn,
|
37
|
+
Self,
|
30
38
|
TextIO,
|
31
39
|
TypeVar,
|
32
40
|
assert_never,
|
@@ -42,7 +50,7 @@ from utilities.datetime import (
|
|
42
50
|
get_now,
|
43
51
|
round_datetime,
|
44
52
|
)
|
45
|
-
from utilities.errors import repr_error
|
53
|
+
from utilities.errors import ImpossibleCaseError, repr_error
|
46
54
|
from utilities.functions import ensure_int, ensure_not_none, get_class_name
|
47
55
|
from utilities.reprlib import get_repr
|
48
56
|
from utilities.sentinel import Sentinel, sentinel
|
@@ -60,6 +68,7 @@ if TYPE_CHECKING:
|
|
60
68
|
from asyncio.subprocess import Process
|
61
69
|
from collections.abc import AsyncIterator, Sequence
|
62
70
|
from contextvars import Context
|
71
|
+
from types import TracebackType
|
63
72
|
|
64
73
|
from utilities.types import Duration
|
65
74
|
|
@@ -125,26 +134,94 @@ class EnhancedTaskGroup(TaskGroup):
|
|
125
134
|
class InfiniteLooper(ABC, Generic[THashable]):
|
126
135
|
"""An infinite loop which can throw exceptions by setting events."""
|
127
136
|
|
128
|
-
sleep_core: DurationOrEveryDuration = SECOND
|
129
|
-
sleep_restart: DurationOrEveryDuration = MINUTE
|
130
|
-
|
137
|
+
sleep_core: DurationOrEveryDuration = field(default=SECOND, repr=False)
|
138
|
+
sleep_restart: DurationOrEveryDuration = field(default=MINUTE, repr=False)
|
139
|
+
duration: Duration | None = field(default=None, repr=False)
|
140
|
+
logger: str | None = field(default=None, repr=False)
|
141
|
+
_await_upon_aenter: bool = field(default=True, init=False, repr=False)
|
142
|
+
_depth: int = field(default=0, init=False, repr=False)
|
131
143
|
_events: Mapping[THashable | None, Event] = field(
|
132
144
|
default_factory=dict, init=False, repr=False, hash=False
|
133
145
|
)
|
146
|
+
_stack: AsyncExitStack = field(
|
147
|
+
default_factory=AsyncExitStack, init=False, repr=False
|
148
|
+
)
|
149
|
+
_task: Task[None] | None = field(default=None, init=False, repr=False)
|
134
150
|
|
135
151
|
def __post_init__(self) -> None:
|
136
152
|
self._events = {
|
137
153
|
event: Event() for event, _ in self._yield_events_and_exceptions()
|
138
154
|
}
|
139
155
|
|
140
|
-
async def
|
141
|
-
"""
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
156
|
+
async def __aenter__(self) -> Self:
|
157
|
+
"""Context manager entry."""
|
158
|
+
if (self._task is None) and (self._depth == 0):
|
159
|
+
_ = await self._stack.__aenter__()
|
160
|
+
self._task = create_task(self._run_looper())
|
161
|
+
if self._await_upon_aenter:
|
162
|
+
with suppress(CancelledError):
|
163
|
+
await self._task
|
164
|
+
elif (self._task is not None) and (self._depth >= 1):
|
165
|
+
...
|
166
|
+
else:
|
167
|
+
raise ImpossibleCaseError( # pragma: no cover
|
168
|
+
case=[f"{self._task=}", f"{self._depth=}"]
|
169
|
+
)
|
170
|
+
self._depth += 1
|
171
|
+
return self
|
172
|
+
|
173
|
+
async def __aexit__(
|
174
|
+
self,
|
175
|
+
exc_type: type[BaseException] | None = None,
|
176
|
+
exc_value: BaseException | None = None,
|
177
|
+
traceback: TracebackType | None = None,
|
178
|
+
) -> None:
|
179
|
+
"""Context manager exit."""
|
180
|
+
_ = (exc_type, exc_value, traceback)
|
181
|
+
if (self._task is None) or (self._depth == 0):
|
182
|
+
raise ImpossibleCaseError( # pragma: no cover
|
183
|
+
case=[f"{self._task=}", f"{self._depth=}"]
|
184
|
+
)
|
185
|
+
self._depth -= 1
|
186
|
+
if self._depth == 0:
|
187
|
+
_ = await self._stack.__aexit__(exc_type, exc_value, traceback)
|
188
|
+
with suppress(CancelledError):
|
189
|
+
await self._task
|
190
|
+
self._task = None
|
191
|
+
with suppress(Exception):
|
192
|
+
await self._teardown()
|
193
|
+
|
194
|
+
async def stop(self) -> None:
|
195
|
+
"""Stop the service."""
|
196
|
+
if self._task is None:
|
197
|
+
raise ImpossibleCaseError(case=[f"{self._task=}"]) # pragma: no cover
|
198
|
+
with suppress(CancelledError):
|
199
|
+
_ = self._task.cancel()
|
146
200
|
|
147
201
|
async def _run_looper(self) -> None:
|
202
|
+
"""Run the looper."""
|
203
|
+
match self.duration:
|
204
|
+
case None:
|
205
|
+
await self._run_looper_without_timeout()
|
206
|
+
case int() | float() | dt.timedelta() as duration:
|
207
|
+
try:
|
208
|
+
async with timeout_dur(duration=duration):
|
209
|
+
return await self._run_looper_without_timeout()
|
210
|
+
except TimeoutError:
|
211
|
+
await self.stop()
|
212
|
+
case _ as never:
|
213
|
+
assert_never(never)
|
214
|
+
return None
|
215
|
+
|
216
|
+
async def _run_looper_without_timeout(self) -> None:
|
217
|
+
"""Run the looper without a timeout."""
|
218
|
+
coroutines = list(self._yield_coroutines())
|
219
|
+
loopers = list(self._yield_loopers())
|
220
|
+
if (len(coroutines) == 0) and (len(loopers) == 0):
|
221
|
+
return await self._run_looper_by_itself()
|
222
|
+
return await self._run_looper_with_others(coroutines, loopers)
|
223
|
+
|
224
|
+
async def _run_looper_by_itself(self) -> None:
|
148
225
|
"""Run the looper by itself."""
|
149
226
|
while True:
|
150
227
|
try:
|
@@ -171,20 +248,31 @@ class InfiniteLooper(ABC, Generic[THashable]):
|
|
171
248
|
raise
|
172
249
|
except Exception as error: # noqa: BLE001
|
173
250
|
self._error_upon_core(error)
|
174
|
-
|
251
|
+
try:
|
252
|
+
await self._teardown()
|
253
|
+
except Exception as error: # noqa: BLE001
|
254
|
+
self._error_upon_teardown(error)
|
255
|
+
finally:
|
256
|
+
await self._run_sleep(self.sleep_restart)
|
175
257
|
|
176
|
-
async def
|
177
|
-
self,
|
258
|
+
async def _run_looper_with_others(
|
259
|
+
self,
|
260
|
+
coroutines: Iterable[Callable[[], Coroutine1[None]]],
|
261
|
+
loopers: Iterable[InfiniteLooper[Any]],
|
262
|
+
/,
|
178
263
|
) -> None:
|
179
264
|
"""Run multiple loopers."""
|
180
265
|
while True:
|
181
266
|
self._reset_events()
|
182
267
|
try:
|
183
|
-
async with TaskGroup() as tg:
|
184
|
-
_ = tg.create_task(self.
|
268
|
+
async with TaskGroup() as tg, AsyncExitStack() as stack:
|
269
|
+
_ = tg.create_task(self._run_looper_by_itself())
|
185
270
|
_ = [tg.create_task(c()) for c in coroutines]
|
271
|
+
_ = [
|
272
|
+
tg.create_task(stack.enter_async_context(lo)) for lo in loopers
|
273
|
+
]
|
186
274
|
except ExceptionGroup as error:
|
187
|
-
self.
|
275
|
+
self._error_group_upon_others(error)
|
188
276
|
await self._run_sleep(self.sleep_restart)
|
189
277
|
|
190
278
|
async def _initialize(self) -> None:
|
@@ -193,6 +281,9 @@ class InfiniteLooper(ABC, Generic[THashable]):
|
|
193
281
|
async def _core(self) -> None:
|
194
282
|
"""Run the core part of the loop."""
|
195
283
|
|
284
|
+
async def _teardown(self) -> None:
|
285
|
+
"""Tear down the loop."""
|
286
|
+
|
196
287
|
def _error_upon_initialize(self, error: Exception, /) -> None:
|
197
288
|
"""Handle any errors upon initializing the looper."""
|
198
289
|
if self.logger is not None:
|
@@ -213,7 +304,17 @@ class InfiniteLooper(ABC, Generic[THashable]):
|
|
213
304
|
self._sleep_restart_desc,
|
214
305
|
)
|
215
306
|
|
216
|
-
def
|
307
|
+
def _error_upon_teardown(self, error: Exception, /) -> None:
|
308
|
+
"""Handle any errors upon tearing down the looper."""
|
309
|
+
if self.logger is not None:
|
310
|
+
getLogger(name=self.logger).error(
|
311
|
+
"%r encountered %r whilst tearing down; sleeping %s...",
|
312
|
+
get_class_name(self),
|
313
|
+
repr_error(error),
|
314
|
+
self._sleep_restart_desc,
|
315
|
+
)
|
316
|
+
|
317
|
+
def _error_group_upon_others(self, group: ExceptionGroup, /) -> None:
|
217
318
|
"""Handle any errors upon running the core function."""
|
218
319
|
if self.logger is not None:
|
219
320
|
errors = group.exceptions
|
@@ -269,15 +370,19 @@ class InfiniteLooper(ABC, Generic[THashable]):
|
|
269
370
|
raise _InfiniteLooperNoSuchEventError(looper=self, event=event) from None
|
270
371
|
event_obj.set()
|
271
372
|
|
373
|
+
def _yield_events_and_exceptions(
|
374
|
+
self,
|
375
|
+
) -> Iterator[tuple[THashable | None, MaybeType[Exception]]]:
|
376
|
+
"""Yield the events & exceptions."""
|
377
|
+
yield (None, _InfiniteLooperDefaultEventError(looper=self))
|
378
|
+
|
272
379
|
def _yield_coroutines(self) -> Iterator[Callable[[], Coroutine1[None]]]:
|
273
380
|
"""Yield any other coroutines which must also be run."""
|
274
381
|
yield from []
|
275
382
|
|
276
|
-
def
|
277
|
-
|
278
|
-
|
279
|
-
"""Yield the events & exceptions."""
|
280
|
-
yield (None, _InfiniteLooperDefaultEventError)
|
383
|
+
def _yield_loopers(self) -> Iterator[InfiniteLooper[Any]]:
|
384
|
+
"""Yield any other loopers which must also be run."""
|
385
|
+
yield from []
|
281
386
|
|
282
387
|
|
283
388
|
@dataclass(kw_only=True, slots=True)
|
@@ -309,6 +414,7 @@ class InfiniteQueueLooper(InfiniteLooper[THashable], Generic[THashable, _T]):
|
|
309
414
|
"""An infinite loop which processes a queue."""
|
310
415
|
|
311
416
|
queue_type: type[Queue[_T]] = field(default=Queue, repr=False)
|
417
|
+
_await_upon_aenter: bool = field(default=False, init=False, repr=False)
|
312
418
|
_queue: Queue[_T] = field(init=False)
|
313
419
|
|
314
420
|
@override
|
@@ -346,6 +452,7 @@ class InfiniteQueueLooper(InfiniteLooper[THashable], Generic[THashable, _T]):
|
|
346
452
|
"""Run until the queue is empty."""
|
347
453
|
while not self.empty():
|
348
454
|
await self._process_items(*get_items_nowait(self._queue))
|
455
|
+
await self.stop()
|
349
456
|
|
350
457
|
@override
|
351
458
|
def _error_upon_core(self, error: Exception, /) -> None:
|
@@ -353,12 +460,12 @@ class InfiniteQueueLooper(InfiniteLooper[THashable], Generic[THashable, _T]):
|
|
353
460
|
if self.logger is not None:
|
354
461
|
if isinstance(error, InfiniteQueueLooperError):
|
355
462
|
getLogger(name=self.logger).error(
|
356
|
-
"%r encountered %s whilst processing %d item(s) %s; sleeping
|
463
|
+
"%r encountered %s whilst processing %d item(s) %s; sleeping %s...",
|
357
464
|
get_class_name(self),
|
358
465
|
repr_error(error.error),
|
359
466
|
len(error.items),
|
360
467
|
get_repr(error.items),
|
361
|
-
self.
|
468
|
+
self._sleep_restart_desc,
|
362
469
|
)
|
363
470
|
else:
|
364
471
|
super()._error_upon_core(error) # pragma: no cover
|
@@ -370,10 +477,6 @@ class InfiniteQueueLooperError(Exception, Generic[_T]):
|
|
370
477
|
items: Sequence[_T]
|
371
478
|
error: Exception
|
372
479
|
|
373
|
-
@override
|
374
|
-
def __str__(self) -> str:
|
375
|
-
return f"{get_class_name(self.looper)!r} encountered {repr_error(self.error)} whilst processing {len(self.items)} item(s): {get_repr(self.items)}"
|
376
|
-
|
377
480
|
|
378
481
|
##
|
379
482
|
|
utilities/fastapi.py
CHANGED
utilities/polars.py
CHANGED
@@ -117,7 +117,7 @@ if TYPE_CHECKING:
|
|
117
117
|
JoinStrategy, # pyright: ignore[reportPrivateImportUsage]
|
118
118
|
JoinValidation, # pyright: ignore[reportPrivateImportUsage]
|
119
119
|
PolarsDataType, # pyright: ignore[reportPrivateImportUsage]
|
120
|
-
|
120
|
+
QuantileMethod, # pyright: ignore[reportPrivateImportUsage]
|
121
121
|
SchemaDict, # pyright: ignore[reportPrivateImportUsage]
|
122
122
|
TimeUnit, # pyright: ignore[reportPrivateImportUsage]
|
123
123
|
)
|
@@ -939,7 +939,7 @@ def cross_rolling_quantile(
|
|
939
939
|
quantile: float,
|
940
940
|
/,
|
941
941
|
*,
|
942
|
-
interpolation:
|
942
|
+
interpolation: QuantileMethod = "nearest",
|
943
943
|
window_size: int = 2,
|
944
944
|
weights: list[float] | None = None,
|
945
945
|
min_samples: int | None = None,
|
@@ -952,7 +952,7 @@ def cross_rolling_quantile(
|
|
952
952
|
quantile: float,
|
953
953
|
/,
|
954
954
|
*,
|
955
|
-
interpolation:
|
955
|
+
interpolation: QuantileMethod = "nearest",
|
956
956
|
window_size: int = 2,
|
957
957
|
weights: list[float] | None = None,
|
958
958
|
min_samples: int | None = None,
|
@@ -965,7 +965,7 @@ def cross_rolling_quantile(
|
|
965
965
|
quantile: float,
|
966
966
|
/,
|
967
967
|
*,
|
968
|
-
interpolation:
|
968
|
+
interpolation: QuantileMethod = "nearest",
|
969
969
|
window_size: int = 2,
|
970
970
|
weights: list[float] | None = None,
|
971
971
|
min_samples: int | None = None,
|
@@ -977,7 +977,7 @@ def cross_rolling_quantile(
|
|
977
977
|
quantile: float,
|
978
978
|
/,
|
979
979
|
*,
|
980
|
-
interpolation:
|
980
|
+
interpolation: QuantileMethod = "nearest",
|
981
981
|
window_size: int = 2,
|
982
982
|
weights: list[float] | None = None,
|
983
983
|
min_samples: int | None = None,
|
utilities/redis.py
CHANGED
@@ -611,7 +611,7 @@ class Publisher(InfiniteQueueLooper[None, tuple[str, EncodableT]]):
|
|
611
611
|
@override
|
612
612
|
def _yield_events_and_exceptions(
|
613
613
|
self,
|
614
|
-
) -> Iterator[tuple[None, MaybeType[
|
614
|
+
) -> Iterator[tuple[None, MaybeType[Exception]]]:
|
615
615
|
yield (None, PublisherError) # skipif-ci-and-not-linux
|
616
616
|
|
617
617
|
|
utilities/sqlalchemy.py
CHANGED
@@ -640,7 +640,7 @@ class Upserter(InfiniteQueueLooper[None, _InsertItem]):
|
|
640
640
|
@override
|
641
641
|
def _yield_events_and_exceptions(
|
642
642
|
self,
|
643
|
-
) -> Iterator[tuple[None, MaybeType[
|
643
|
+
) -> Iterator[tuple[None, MaybeType[Exception]]]:
|
644
644
|
yield (None, UpserterError)
|
645
645
|
|
646
646
|
|
File without changes
|
File without changes
|