dycw-utilities 0.118.0__py3-none-any.whl → 0.119.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.118.0.dist-info → dycw_utilities-0.119.0.dist-info}/METADATA +27 -27
- {dycw_utilities-0.118.0.dist-info → dycw_utilities-0.119.0.dist-info}/RECORD +12 -12
- utilities/__init__.py +1 -1
- utilities/click.py +19 -19
- utilities/datetime.py +5 -5
- utilities/hypothesis.py +44 -44
- utilities/orjson.py +2 -2
- utilities/period.py +2 -2
- utilities/whenever.py +66 -104
- utilities/zoneinfo.py +3 -3
- {dycw_utilities-0.118.0.dist-info → dycw_utilities-0.119.0.dist-info}/WHEEL +0 -0
- {dycw_utilities-0.118.0.dist-info → dycw_utilities-0.119.0.dist-info}/licenses/LICENSE +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: dycw-utilities
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.119.0
|
4
4
|
Author-email: Derek Wan <d.wan@icloud.com>
|
5
5
|
License-File: LICENSE
|
6
6
|
Requires-Python: >=3.12
|
@@ -26,7 +26,7 @@ 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
27
|
Requires-Dist: polars-lts-cpu<1.30,>=1.29.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.
|
29
|
+
Requires-Dist: whenever<0.9,>=0.8.0; 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
|
@@ -39,20 +39,20 @@ Requires-Dist: cachetools<5.6,>=5.5.2; extra == 'zzz-test-cachetools'
|
|
39
39
|
Provides-Extra: zzz-test-click
|
40
40
|
Requires-Dist: click<8.3,>=8.2.0; extra == 'zzz-test-click'
|
41
41
|
Requires-Dist: sqlalchemy<2.1,>=2.0.41; extra == 'zzz-test-click'
|
42
|
-
Requires-Dist: whenever<0.
|
42
|
+
Requires-Dist: whenever<0.9,>=0.8.0; 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
|
46
|
-
Requires-Dist: cryptography<
|
46
|
+
Requires-Dist: cryptography<45.1,>=45.0.2; extra == 'zzz-test-cryptography'
|
47
47
|
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
51
|
Requires-Dist: polars-lts-cpu<1.30,>=1.29.0; extra == 'zzz-test-dataclasses'
|
52
|
-
Requires-Dist: whenever<0.
|
52
|
+
Requires-Dist: whenever<0.9,>=0.8.0; 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.
|
55
|
+
Requires-Dist: whenever<0.9,>=0.8.0; 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
|
@@ -71,29 +71,29 @@ 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
73
|
Requires-Dist: polars-lts-cpu<1.30,>=1.29.0; extra == 'zzz-test-hashlib'
|
74
|
-
Requires-Dist: whenever<0.
|
74
|
+
Requires-Dist: whenever<0.9,>=0.8.0; 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.
|
78
|
+
Requires-Dist: whenever<0.9,>=0.8.0; 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
83
|
Requires-Dist: hypothesis<6.132,>=6.131.19; extra == 'zzz-test-hypothesis'
|
84
84
|
Requires-Dist: luigi<3.7,>=3.6.0; extra == 'zzz-test-hypothesis'
|
85
|
-
Requires-Dist: numpy<2.3,>=2.2.
|
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'
|
87
87
|
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.
|
91
|
+
Requires-Dist: whenever<0.9,>=0.8.0; 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
95
|
Requires-Dist: polars-lts-cpu<1.30,>=1.29.0; extra == 'zzz-test-iterables'
|
96
|
-
Requires-Dist: whenever<0.
|
96
|
+
Requires-Dist: whenever<0.9,>=0.8.0; 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'
|
@@ -105,24 +105,24 @@ 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.
|
108
|
+
Requires-Dist: whenever<0.9,>=0.8.0; 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.
|
113
|
+
Requires-Dist: whenever<0.9,>=0.8.0; extra == 'zzz-test-luigi'
|
114
114
|
Provides-Extra: zzz-test-math
|
115
|
-
Requires-Dist: numpy<2.3,>=2.2.
|
115
|
+
Requires-Dist: numpy<2.3,>=2.2.6; extra == 'zzz-test-math'
|
116
116
|
Provides-Extra: zzz-test-memory-profiler
|
117
117
|
Requires-Dist: memory-profiler<0.62,>=0.61.0; extra == 'zzz-test-memory-profiler'
|
118
118
|
Provides-Extra: zzz-test-modules
|
119
119
|
Provides-Extra: zzz-test-more-itertools
|
120
120
|
Requires-Dist: more-itertools<10.8,>=10.7.0; extra == 'zzz-test-more-itertools'
|
121
121
|
Provides-Extra: zzz-test-numpy
|
122
|
-
Requires-Dist: numpy<2.3,>=2.2.
|
122
|
+
Requires-Dist: numpy<2.3,>=2.2.6; extra == 'zzz-test-numpy'
|
123
123
|
Provides-Extra: zzz-test-operator
|
124
124
|
Requires-Dist: polars-lts-cpu<1.30,>=1.29.0; extra == 'zzz-test-operator'
|
125
|
-
Requires-Dist: whenever<0.
|
125
|
+
Requires-Dist: whenever<0.9,>=0.8.0; 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
|
@@ -130,7 +130,7 @@ Requires-Dist: orjson<3.11,>=3.10.15; extra == 'zzz-test-orjson'
|
|
130
130
|
Requires-Dist: polars-lts-cpu<1.30,>=1.29.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.
|
133
|
+
Requires-Dist: whenever<0.9,>=0.8.0; 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
|
@@ -138,7 +138,7 @@ 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
140
|
Requires-Dist: polars-lts-cpu<1.30,>=1.29.0; extra == 'zzz-test-polars'
|
141
|
-
Requires-Dist: whenever<0.
|
141
|
+
Requires-Dist: whenever<0.9,>=0.8.0; 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,12 +153,12 @@ 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.
|
156
|
+
Requires-Dist: whenever<0.9,>=0.8.0; 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.
|
161
|
+
Requires-Dist: whenever<0.9,>=0.8.0; 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
|
@@ -168,7 +168,7 @@ 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.
|
171
|
+
Requires-Dist: whenever<0.9,>=0.8.0; 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
|
@@ -194,7 +194,7 @@ Requires-Dist: nest-asyncio<1.7,>=1.6.0; extra == 'zzz-test-sqlalchemy-polars'
|
|
194
194
|
Requires-Dist: polars-lts-cpu<1.30,>=1.29.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.
|
197
|
+
Requires-Dist: whenever<0.9,>=0.8.0; 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.
|
205
|
+
Requires-Dist: whenever<0.9,>=0.8.0; 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.
|
216
|
+
Requires-Dist: whenever<0.9,>=0.8.0; extra == 'zzz-test-traceback'
|
217
217
|
Provides-Extra: zzz-test-types
|
218
218
|
Provides-Extra: zzz-test-typing
|
219
219
|
Requires-Dist: polars-lts-cpu<1.30,>=1.29.0; extra == 'zzz-test-typing'
|
220
|
-
Requires-Dist: whenever<0.
|
220
|
+
Requires-Dist: whenever<0.9,>=0.8.0; 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.
|
228
|
+
Requires-Dist: whenever<0.9,>=0.8.0; 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.
|
232
|
+
Requires-Dist: whenever<0.9,>=0.8.0; extra == 'zzz-test-zoneinfo'
|
233
233
|
Description-Content-Type: text/markdown
|
234
234
|
|
235
235
|
[](https://badge.fury.io/py/dycw-utilities)
|
@@ -1,18 +1,18 @@
|
|
1
|
-
utilities/__init__.py,sha256=
|
1
|
+
utilities/__init__.py,sha256=ayFWZ1qOKB0Lqd63WRIXSBg4vZDal1xvPPVJr5LEPEA,60
|
2
2
|
utilities/altair.py,sha256=Gpja-flOo-Db0PIPJLJsgzAlXWoKUjPU1qY-DQ829ek,9156
|
3
3
|
utilities/astor.py,sha256=xuDUkjq0-b6fhtwjhbnebzbqQZAjMSHR1IIS5uOodVg,777
|
4
4
|
utilities/asyncio.py,sha256=HGX79AKzpQbbDBW3paxAXrhWYeudcJjiO1ETU40d_-8,18463
|
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
|
8
|
-
utilities/click.py,sha256=
|
8
|
+
utilities/click.py,sha256=SRVkUkWxyO_7AaYvvDl0hNCzdpneX04lf1O97i9MfPw,14311
|
9
9
|
utilities/concurrent.py,sha256=s2scTEd2AhXVTW4hpASU2qxV_DiVLALfms55cCQzCvM,2886
|
10
10
|
utilities/contextlib.py,sha256=OOIIEa5lXKGzFAnauaul40nlQnQko6Na4ryiMJcHkIg,478
|
11
11
|
utilities/contextvars.py,sha256=RsSGGrbQqqZ67rOydnM7WWIsM2lIE31UHJLejnHJPWY,505
|
12
12
|
utilities/cryptography.py,sha256=_CiK_K6c_-uQuUhsUNjNjTL-nqxAh4_1zTfS11Xe120,972
|
13
13
|
utilities/cvxpy.py,sha256=Rv1-fD-XYerosCavRF8Pohop2DBkU3AlFaGTfD8AEAA,13776
|
14
14
|
utilities/dataclasses.py,sha256=iiC1wpGXWhaocIikzwBt8bbLWyImoUlOlcDZJGejaIg,33011
|
15
|
-
utilities/datetime.py,sha256=
|
15
|
+
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
|
@@ -24,7 +24,7 @@ utilities/getpass.py,sha256=DfN5UgMAtFCqS3dSfFHUfqIMZX2shXvwphOz_6J6f6A,103
|
|
24
24
|
utilities/git.py,sha256=wpt5dZ5Oi5931pN24_VLZYaQOvmR0OcQuVtgHzFUN1k,2359
|
25
25
|
utilities/hashlib.py,sha256=SVTgtguur0P4elppvzOBbLEjVM3Pea0eWB61yg2ilxo,309
|
26
26
|
utilities/http.py,sha256=WcahTcKYRtZ04WXQoWt5EGCgFPcyHD3EJdlMfxvDt-0,946
|
27
|
-
utilities/hypothesis.py,sha256=
|
27
|
+
utilities/hypothesis.py,sha256=a75izXg9aCBhhDkj_ZgK3TDzlzk38evP8TO7JbYYQvg,46264
|
28
28
|
utilities/importlib.py,sha256=ueY3R39hWrUtrVXs39utM2xDig-eyJfYn1FBVxWb3_w,368
|
29
29
|
utilities/ipython.py,sha256=V2oMYHvEKvlNBzxDXdLvKi48oUq2SclRg5xasjaXStw,763
|
30
30
|
utilities/iterables.py,sha256=prKXBdF5QfLTGC-q4567DwO8xzUng_Z-2a4wBkMqyDo,45360
|
@@ -40,11 +40,11 @@ utilities/more_itertools.py,sha256=6T0225gBFZtv47-B0JRFOKMz836Wg3Hct79ePPLGpuo,5
|
|
40
40
|
utilities/numpy.py,sha256=Xn23sA2ZbVNqwUYEgNJD3XBYH6IbCri_WkHSNhg3NkY,26122
|
41
41
|
utilities/operator.py,sha256=0M2yZJ0PODH47ogFEnkGMBe_cfxwZR02T_92LZVZvHo,3715
|
42
42
|
utilities/optuna.py,sha256=loyJGWTzljgdJaoLhP09PT8Jz6o_pwBOwehY33lHkhw,1923
|
43
|
-
utilities/orjson.py,sha256=
|
43
|
+
utilities/orjson.py,sha256=AvPFxzJdxC-3PBID3cqdiMyN8FeC7aW9QUgGwbvKuAM,36948
|
44
44
|
utilities/os.py,sha256=D_FyyT-6TtqiN9KSS7c9g1fnUtgxmyMtzAjmYLkk46A,3587
|
45
45
|
utilities/parse.py,sha256=vsZ2jf_ceSI_Kta9titixufysJaVXh0Whjz1T4awJZw,18938
|
46
46
|
utilities/pathlib.py,sha256=31WPMXdLIyXgYOMMl_HOI2wlo66MGSE-cgeelk-Lias,1410
|
47
|
-
utilities/period.py,sha256=
|
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
50
|
utilities/polars.py,sha256=fxfSm4xVHwKvRxu50IhYNKCKOagp12FdwsVf04ARKpk,63692
|
@@ -85,10 +85,10 @@ utilities/tzlocal.py,sha256=3upDNFBvGh1l9njmLR2z2S6K6VxQSb7QizYGUbAH3JU,960
|
|
85
85
|
utilities/uuid.py,sha256=jJTFxz-CWgltqNuzmythB7iEQ-Q1mCwPevUfKthZT3c,611
|
86
86
|
utilities/version.py,sha256=QFuyEeQA6jI0ruBEcmhqG36f-etg1AEiD1drBBqhQrs,5358
|
87
87
|
utilities/warnings.py,sha256=un1LvHv70PU-LLv8RxPVmugTzDJkkGXRMZTE2-fTQHw,1771
|
88
|
-
utilities/whenever.py,sha256=
|
88
|
+
utilities/whenever.py,sha256=jS31ZAY5OMxFxLja_Yo5Fidi87Pd-GoVZ7Vi_teqVDA,16743
|
89
89
|
utilities/zipfile.py,sha256=24lQc9ATcJxHXBPc_tBDiJk48pWyRrlxO2fIsFxU0A8,699
|
90
|
-
utilities/zoneinfo.py,sha256=-
|
91
|
-
dycw_utilities-0.
|
92
|
-
dycw_utilities-0.
|
93
|
-
dycw_utilities-0.
|
94
|
-
dycw_utilities-0.
|
90
|
+
utilities/zoneinfo.py,sha256=-5j7IQ9nb7gR43rdgA7ms05im-XuqhAk9EJnQBXxCoQ,1874
|
91
|
+
dycw_utilities-0.119.0.dist-info/METADATA,sha256=XG8mqNyIqDEemm7CPwNSAdYJS_z_rsP8SqlYoT-DEAY,12943
|
92
|
+
dycw_utilities-0.119.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
93
|
+
dycw_utilities-0.119.0.dist-info/licenses/LICENSE,sha256=gppZp16M6nSVpBbUBrNL6JuYfvKwZiKgV7XoKKsHzqo,1066
|
94
|
+
dycw_utilities-0.119.0.dist-info/RECORD,,
|
utilities/__init__.py
CHANGED
utilities/click.py
CHANGED
@@ -131,10 +131,10 @@ class Enum(ParamType, Generic[TEnum]):
|
|
131
131
|
return _make_metavar(param, desc)
|
132
132
|
|
133
133
|
|
134
|
-
class
|
135
|
-
"""A
|
134
|
+
class Month(ParamType):
|
135
|
+
"""A month-valued parameter."""
|
136
136
|
|
137
|
-
name = "
|
137
|
+
name = "month"
|
138
138
|
|
139
139
|
@override
|
140
140
|
def __repr__(self) -> str:
|
@@ -142,21 +142,19 @@ class LocalDateTime(ParamType):
|
|
142
142
|
|
143
143
|
@override
|
144
144
|
def convert(
|
145
|
-
self, value:
|
146
|
-
) ->
|
147
|
-
"""Convert a value into the `
|
148
|
-
from utilities.whenever import EnsureLocalDateTimeError, ensure_local_datetime
|
149
|
-
|
145
|
+
self, value: MonthLike, param: Parameter | None, ctx: Context | None
|
146
|
+
) -> utilities.datetime.Month:
|
147
|
+
"""Convert a value into the `Month` type."""
|
150
148
|
try:
|
151
|
-
return
|
152
|
-
except
|
149
|
+
return ensure_month(value)
|
150
|
+
except EnsureMonthError as error:
|
153
151
|
self.fail(str(error), param, ctx)
|
154
152
|
|
155
153
|
|
156
|
-
class
|
157
|
-
"""A
|
154
|
+
class PlainDateTime(ParamType):
|
155
|
+
"""A local-datetime-valued parameter."""
|
158
156
|
|
159
|
-
name = "
|
157
|
+
name = "plain datetime"
|
160
158
|
|
161
159
|
@override
|
162
160
|
def __repr__(self) -> str:
|
@@ -164,12 +162,14 @@ class Month(ParamType):
|
|
164
162
|
|
165
163
|
@override
|
166
164
|
def convert(
|
167
|
-
self, value:
|
168
|
-
) ->
|
169
|
-
"""Convert a value into the `
|
165
|
+
self, value: DateTimeLike, param: Parameter | None, ctx: Context | None
|
166
|
+
) -> dt.date:
|
167
|
+
"""Convert a value into the `LocalDateTime` type."""
|
168
|
+
from utilities.whenever import EnsurePlainDateTimeError, ensure_plain_datetime
|
169
|
+
|
170
170
|
try:
|
171
|
-
return
|
172
|
-
except
|
171
|
+
return ensure_plain_datetime(value)
|
172
|
+
except EnsurePlainDateTimeError as error:
|
173
173
|
self.fail(str(error), param, ctx)
|
174
174
|
|
175
175
|
|
@@ -506,8 +506,8 @@ __all__ = [
|
|
506
506
|
"ListParameter",
|
507
507
|
"ListStrs",
|
508
508
|
"ListUUIDs",
|
509
|
-
"LocalDateTime",
|
510
509
|
"Month",
|
510
|
+
"PlainDateTime",
|
511
511
|
"Time",
|
512
512
|
"Timedelta",
|
513
513
|
"ZonedDateTime",
|
utilities/datetime.py
CHANGED
@@ -457,7 +457,7 @@ class EnsureMonthError(Exception):
|
|
457
457
|
|
458
458
|
|
459
459
|
def format_datetime_local_and_utc(datetime: dt.datetime, /) -> str:
|
460
|
-
"""Format a
|
460
|
+
"""Format a plain datetime locally & in UTC."""
|
461
461
|
time_zone = ensure_time_zone(datetime)
|
462
462
|
if time_zone is UTC:
|
463
463
|
return datetime.strftime("%Y-%m-%d %H:%M:%S (%a, UTC)")
|
@@ -706,8 +706,8 @@ def is_integral_timedelta(duration: Duration, /) -> bool:
|
|
706
706
|
##
|
707
707
|
|
708
708
|
|
709
|
-
def
|
710
|
-
"""Check if an object is a
|
709
|
+
def is_plain_datetime(obj: Any, /) -> TypeGuard[dt.datetime]:
|
710
|
+
"""Check if an object is a plain datetime."""
|
711
711
|
return isinstance(obj, dt.datetime) and (obj.tzinfo is None)
|
712
712
|
|
713
713
|
|
@@ -1105,7 +1105,7 @@ class SerializeCompactError(Exception):
|
|
1105
1105
|
|
1106
1106
|
@override
|
1107
1107
|
def __str__(self) -> str:
|
1108
|
-
return f"Unable to serialize
|
1108
|
+
return f"Unable to serialize plain datetime {self.datetime}"
|
1109
1109
|
|
1110
1110
|
|
1111
1111
|
def parse_date_compact(text: str, /) -> dt.date:
|
@@ -1388,7 +1388,7 @@ __all__ = [
|
|
1388
1388
|
"get_today",
|
1389
1389
|
"get_years",
|
1390
1390
|
"is_integral_timedelta",
|
1391
|
-
"
|
1391
|
+
"is_plain_datetime",
|
1392
1392
|
"is_weekday",
|
1393
1393
|
"is_zero_time",
|
1394
1394
|
"is_zoned_datetime",
|
utilities/hypothesis.py
CHANGED
@@ -642,43 +642,6 @@ def lists_fixed_length(
|
|
642
642
|
##
|
643
643
|
|
644
644
|
|
645
|
-
@composite
|
646
|
-
def local_datetimes(
|
647
|
-
draw: DrawFn,
|
648
|
-
/,
|
649
|
-
*,
|
650
|
-
min_value: MaybeSearchStrategy[dt.datetime] = DATETIME_MIN_NAIVE,
|
651
|
-
max_value: MaybeSearchStrategy[dt.datetime] = DATETIME_MAX_NAIVE,
|
652
|
-
round_: RoundMode | None = None,
|
653
|
-
timedelta: dt.timedelta | None = None,
|
654
|
-
rel_tol: float | None = None,
|
655
|
-
abs_tol: float | None = None,
|
656
|
-
) -> dt.datetime:
|
657
|
-
"""Strategy for generating local datetimes."""
|
658
|
-
min_value_, max_value_ = [draw2(draw, v) for v in [min_value, max_value]]
|
659
|
-
datetime = draw(datetimes(min_value=min_value_, max_value=max_value_))
|
660
|
-
if round_ is not None:
|
661
|
-
if timedelta is None:
|
662
|
-
raise LocalDateTimesError(round_=round_)
|
663
|
-
datetime = round_datetime(
|
664
|
-
datetime, timedelta, mode=round_, rel_tol=rel_tol, abs_tol=abs_tol
|
665
|
-
)
|
666
|
-
_ = assume(min_value_ <= datetime <= max_value_)
|
667
|
-
return datetime
|
668
|
-
|
669
|
-
|
670
|
-
@dataclass(kw_only=True, slots=True)
|
671
|
-
class LocalDateTimesError(Exception):
|
672
|
-
round_: RoundMode
|
673
|
-
|
674
|
-
@override
|
675
|
-
def __str__(self) -> str:
|
676
|
-
return "Rounding requires a timedelta; got None"
|
677
|
-
|
678
|
-
|
679
|
-
##
|
680
|
-
|
681
|
-
|
682
645
|
@composite
|
683
646
|
def min_and_max_datetimes(
|
684
647
|
draw: DrawFn,
|
@@ -991,6 +954,43 @@ def paths() -> SearchStrategy[Path]:
|
|
991
954
|
##
|
992
955
|
|
993
956
|
|
957
|
+
@composite
|
958
|
+
def plain_datetimes(
|
959
|
+
draw: DrawFn,
|
960
|
+
/,
|
961
|
+
*,
|
962
|
+
min_value: MaybeSearchStrategy[dt.datetime] = DATETIME_MIN_NAIVE,
|
963
|
+
max_value: MaybeSearchStrategy[dt.datetime] = DATETIME_MAX_NAIVE,
|
964
|
+
round_: RoundMode | None = None,
|
965
|
+
timedelta: dt.timedelta | None = None,
|
966
|
+
rel_tol: float | None = None,
|
967
|
+
abs_tol: float | None = None,
|
968
|
+
) -> dt.datetime:
|
969
|
+
"""Strategy for generating plain datetimes."""
|
970
|
+
min_value_, max_value_ = [draw2(draw, v) for v in [min_value, max_value]]
|
971
|
+
datetime = draw(datetimes(min_value=min_value_, max_value=max_value_))
|
972
|
+
if round_ is not None:
|
973
|
+
if timedelta is None:
|
974
|
+
raise PlainDateTimesError(round_=round_)
|
975
|
+
datetime = round_datetime(
|
976
|
+
datetime, timedelta, mode=round_, rel_tol=rel_tol, abs_tol=abs_tol
|
977
|
+
)
|
978
|
+
_ = assume(min_value_ <= datetime <= max_value_)
|
979
|
+
return datetime
|
980
|
+
|
981
|
+
|
982
|
+
@dataclass(kw_only=True, slots=True)
|
983
|
+
class PlainDateTimesError(Exception):
|
984
|
+
round_: RoundMode
|
985
|
+
|
986
|
+
@override
|
987
|
+
def __str__(self) -> str:
|
988
|
+
return "Rounding requires a timedelta; got None"
|
989
|
+
|
990
|
+
|
991
|
+
##
|
992
|
+
|
993
|
+
|
994
994
|
@composite
|
995
995
|
def random_states(
|
996
996
|
draw: DrawFn, /, *, seed: MaybeSearchStrategy[int | None] = None
|
@@ -1478,7 +1478,7 @@ def zoned_datetimes(
|
|
1478
1478
|
) -> dt.datetime:
|
1479
1479
|
"""Strategy for generating zoned datetimes."""
|
1480
1480
|
from utilities.whenever import (
|
1481
|
-
|
1481
|
+
CheckValidZonedDateTimeError,
|
1482
1482
|
check_valid_zoned_datetime,
|
1483
1483
|
)
|
1484
1484
|
|
@@ -1496,7 +1496,7 @@ def zoned_datetimes(
|
|
1496
1496
|
max_value_ = max_value_.astimezone(time_zone_)
|
1497
1497
|
try:
|
1498
1498
|
datetime = draw(
|
1499
|
-
|
1499
|
+
plain_datetimes(
|
1500
1500
|
min_value=min_value_.replace(tzinfo=None),
|
1501
1501
|
max_value=max_value_.replace(tzinfo=None),
|
1502
1502
|
round_=round_,
|
@@ -1505,13 +1505,13 @@ def zoned_datetimes(
|
|
1505
1505
|
abs_tol=abs_tol,
|
1506
1506
|
)
|
1507
1507
|
)
|
1508
|
-
except
|
1508
|
+
except PlainDateTimesError as error:
|
1509
1509
|
raise ZonedDateTimesError(round_=error.round_) from None
|
1510
1510
|
datetime = datetime.replace(tzinfo=time_zone_)
|
1511
1511
|
_ = assume(min_value_ <= datetime <= max_value_)
|
1512
1512
|
if valid:
|
1513
1513
|
with assume_does_not_raise( # skipif-ci-and-windows
|
1514
|
-
|
1514
|
+
CheckValidZonedDateTimeError
|
1515
1515
|
):
|
1516
1516
|
check_valid_zoned_datetime(datetime)
|
1517
1517
|
return datetime
|
@@ -1528,8 +1528,8 @@ class ZonedDateTimesError(Exception):
|
|
1528
1528
|
|
1529
1529
|
__all__ = [
|
1530
1530
|
"Draw2Error",
|
1531
|
-
"LocalDateTimesError",
|
1532
1531
|
"MaybeSearchStrategy",
|
1532
|
+
"PlainDateTimesError",
|
1533
1533
|
"Shape",
|
1534
1534
|
"ZonedDateTimesError",
|
1535
1535
|
"assume_does_not_raise",
|
@@ -1548,8 +1548,6 @@ __all__ = [
|
|
1548
1548
|
"int64s",
|
1549
1549
|
"int_arrays",
|
1550
1550
|
"lists_fixed_length",
|
1551
|
-
"local_datetimes",
|
1552
|
-
"local_datetimes",
|
1553
1551
|
"min_and_max_datetimes",
|
1554
1552
|
"min_and_maybe_max_datetimes",
|
1555
1553
|
"min_and_maybe_max_sizes",
|
@@ -1559,6 +1557,8 @@ __all__ = [
|
|
1559
1557
|
"numbers",
|
1560
1558
|
"pairs",
|
1561
1559
|
"paths",
|
1560
|
+
"plain_datetimes",
|
1561
|
+
"plain_datetimes",
|
1562
1562
|
"random_states",
|
1563
1563
|
"sentinels",
|
1564
1564
|
"sets_fixed_length",
|
utilities/orjson.py
CHANGED
@@ -48,7 +48,7 @@ from utilities.uuid import UUID_PATTERN
|
|
48
48
|
from utilities.version import Version, parse_version
|
49
49
|
from utilities.whenever import (
|
50
50
|
parse_date,
|
51
|
-
|
51
|
+
parse_plain_datetime,
|
52
52
|
parse_time,
|
53
53
|
parse_timedelta,
|
54
54
|
parse_zoned_datetime,
|
@@ -424,7 +424,7 @@ def _object_hook(
|
|
424
424
|
if match := _FLOAT_PATTERN.search(text):
|
425
425
|
return float(match.group(1))
|
426
426
|
if match := _LOCAL_DATETIME_PATTERN.search(text):
|
427
|
-
return
|
427
|
+
return parse_plain_datetime(match.group(1))
|
428
428
|
if match := _PATH_PATTERN.search(text):
|
429
429
|
return Path(match.group(1))
|
430
430
|
if match := _TIME_PATTERN.search(text):
|
utilities/period.py
CHANGED
@@ -23,7 +23,7 @@ from utilities.sentinel import Sentinel, sentinel
|
|
23
23
|
from utilities.typing import is_instance_gen
|
24
24
|
from utilities.whenever import (
|
25
25
|
serialize_date,
|
26
|
-
|
26
|
+
serialize_plain_datetime,
|
27
27
|
serialize_zoned_datetime,
|
28
28
|
)
|
29
29
|
from utilities.zoneinfo import EnsureTimeZoneError, ensure_time_zone
|
@@ -137,7 +137,7 @@ class Period(Generic[_TPeriod]):
|
|
137
137
|
)
|
138
138
|
return f"{cls}({start}, {end})"
|
139
139
|
start, end = (
|
140
|
-
|
140
|
+
serialize_plain_datetime(t.replace(tzinfo=None))
|
141
141
|
for t in [result.start, result.end]
|
142
142
|
)
|
143
143
|
return f"{cls}({start}, {end}, {time_zone})"
|
utilities/whenever.py
CHANGED
@@ -5,9 +5,15 @@ import re
|
|
5
5
|
from contextlib import suppress
|
6
6
|
from dataclasses import dataclass
|
7
7
|
from typing import TYPE_CHECKING, override
|
8
|
-
from zoneinfo import ZoneInfo
|
9
8
|
|
10
|
-
from whenever import
|
9
|
+
from whenever import (
|
10
|
+
Date,
|
11
|
+
DateTimeDelta,
|
12
|
+
PlainDateTime,
|
13
|
+
Time,
|
14
|
+
TimeZoneNotFoundError,
|
15
|
+
ZonedDateTime,
|
16
|
+
)
|
11
17
|
|
12
18
|
from utilities.datetime import (
|
13
19
|
_MICROSECONDS_PER_DAY,
|
@@ -37,7 +43,7 @@ if TYPE_CHECKING:
|
|
37
43
|
)
|
38
44
|
|
39
45
|
|
40
|
-
MAX_SERIALIZABLE_TIMEDELTA = dt.timedelta(days=
|
46
|
+
MAX_SERIALIZABLE_TIMEDELTA = dt.timedelta(days=3652060, microseconds=-1)
|
41
47
|
MIN_SERIALIZABLE_TIMEDELTA = -MAX_SERIALIZABLE_TIMEDELTA
|
42
48
|
|
43
49
|
|
@@ -48,19 +54,33 @@ def check_valid_zoned_datetime(datetime: dt.datetime, /) -> None:
|
|
48
54
|
"""Check if a zoned datetime is valid."""
|
49
55
|
time_zone = ensure_time_zone(datetime) # skipif-ci-and-windows
|
50
56
|
datetime2 = datetime.replace(tzinfo=time_zone) # skipif-ci-and-windows
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
+
try: # skipif-ci-and-windows
|
58
|
+
result = (
|
59
|
+
ZonedDateTime.from_py_datetime(datetime2)
|
60
|
+
.to_tz(get_time_zone_name(UTC))
|
61
|
+
.to_tz(get_time_zone_name(time_zone))
|
62
|
+
.py_datetime()
|
63
|
+
)
|
64
|
+
except TimeZoneNotFoundError: # pragma: no cover
|
65
|
+
raise _CheckValidZonedDateTimeInvalidTimeZoneError(datetime=datetime) from None
|
57
66
|
if result != datetime2: # skipif-ci-and-windows
|
58
|
-
raise
|
67
|
+
raise _CheckValidZonedDateTimeUnequalError(datetime=datetime, result=result)
|
59
68
|
|
60
69
|
|
61
70
|
@dataclass(kw_only=True, slots=True)
|
62
|
-
class
|
71
|
+
class CheckValidZonedDateTimeError(Exception):
|
63
72
|
datetime: dt.datetime
|
73
|
+
|
74
|
+
|
75
|
+
@dataclass(kw_only=True, slots=True)
|
76
|
+
class _CheckValidZonedDateTimeInvalidTimeZoneError(CheckValidZonedDateTimeError):
|
77
|
+
@override
|
78
|
+
def __str__(self) -> str:
|
79
|
+
return f"Invalid timezone; got {self.datetime.tzinfo}" # pragma: no cover
|
80
|
+
|
81
|
+
|
82
|
+
@dataclass(kw_only=True, slots=True)
|
83
|
+
class _CheckValidZonedDateTimeUnequalError(CheckValidZonedDateTimeError):
|
64
84
|
result: dt.datetime
|
65
85
|
|
66
86
|
@override
|
@@ -138,23 +158,23 @@ class EnsureDurationError(Exception):
|
|
138
158
|
##
|
139
159
|
|
140
160
|
|
141
|
-
def
|
142
|
-
"""Ensure the object is a
|
161
|
+
def ensure_plain_datetime(datetime: DateTimeLike, /) -> dt.datetime:
|
162
|
+
"""Ensure the object is a plain datetime."""
|
143
163
|
if isinstance(datetime, dt.datetime):
|
144
164
|
return datetime
|
145
165
|
try:
|
146
|
-
return
|
147
|
-
except
|
148
|
-
raise
|
166
|
+
return parse_plain_datetime(datetime)
|
167
|
+
except ParsePlainDateTimeError as error:
|
168
|
+
raise EnsurePlainDateTimeError(datetime=error.datetime) from None
|
149
169
|
|
150
170
|
|
151
171
|
@dataclass(kw_only=True, slots=True)
|
152
|
-
class
|
172
|
+
class EnsurePlainDateTimeError(Exception):
|
153
173
|
datetime: str
|
154
174
|
|
155
175
|
@override
|
156
176
|
def __str__(self) -> str:
|
157
|
-
return f"Unable to ensure
|
177
|
+
return f"Unable to ensure plain datetime; got {self.datetime!r}"
|
158
178
|
|
159
179
|
|
160
180
|
##
|
@@ -242,7 +262,6 @@ class EnsureZonedDateTimeError(Exception):
|
|
242
262
|
##
|
243
263
|
|
244
264
|
|
245
|
-
_PARSE_DATE_YYYYMMDD_REGEX = re.compile(r"^(\d{4})(\d{2})(\d{2})$")
|
246
265
|
_PARSE_DATE_YYMMDD_REGEX = re.compile(r"^(\d{2})(\d{2})(\d{2})$")
|
247
266
|
|
248
267
|
|
@@ -250,19 +269,14 @@ def parse_date(date: str, /) -> dt.date:
|
|
250
269
|
"""Parse a string into a date."""
|
251
270
|
try:
|
252
271
|
w_date = Date.parse_common_iso(date)
|
253
|
-
except ValueError:
|
254
|
-
pass
|
255
|
-
else:
|
256
|
-
return w_date.py_date()
|
257
|
-
try:
|
258
|
-
((year, month, day),) = _PARSE_DATE_YYYYMMDD_REGEX.findall(date)
|
259
272
|
except ValueError:
|
260
273
|
try:
|
261
274
|
((year2, month, day),) = _PARSE_DATE_YYMMDD_REGEX.findall(date)
|
262
275
|
except ValueError:
|
263
276
|
raise ParseDateError(date=date) from None
|
264
277
|
year = parse_two_digit_year(year2)
|
265
|
-
|
278
|
+
return dt.date(year=int(year), month=int(month), day=int(day))
|
279
|
+
return w_date.py_date()
|
266
280
|
|
267
281
|
|
268
282
|
@dataclass(kw_only=True, slots=True)
|
@@ -279,8 +293,8 @@ class ParseDateError(Exception):
|
|
279
293
|
|
280
294
|
def parse_datetime(datetime: str, /) -> dt.datetime:
|
281
295
|
"""Parse a string into a datetime."""
|
282
|
-
with suppress(
|
283
|
-
return
|
296
|
+
with suppress(ParsePlainDateTimeError):
|
297
|
+
return parse_plain_datetime(datetime)
|
284
298
|
with suppress(ParseZonedDateTimeError):
|
285
299
|
return parse_zoned_datetime(datetime)
|
286
300
|
raise ParseDateTimeError(datetime=datetime) from None
|
@@ -320,48 +334,22 @@ class ParseDurationError(Exception):
|
|
320
334
|
##
|
321
335
|
|
322
336
|
|
323
|
-
|
324
|
-
|
325
|
-
)
|
326
|
-
|
327
|
-
|
328
|
-
def parse_local_datetime(datetime: str, /) -> dt.datetime:
|
329
|
-
"""Parse a string into a local datetime."""
|
330
|
-
try:
|
331
|
-
ldt = LocalDateTime.parse_common_iso(datetime)
|
332
|
-
except ValueError:
|
333
|
-
pass
|
334
|
-
else:
|
335
|
-
return ldt.py_datetime()
|
337
|
+
def parse_plain_datetime(datetime: str, /) -> dt.datetime:
|
338
|
+
"""Parse a string into a plain datetime."""
|
336
339
|
try:
|
337
|
-
|
338
|
-
_PARSE_LOCAL_DATETIME_REGEX.findall(datetime)
|
339
|
-
)
|
340
|
-
except ValueError:
|
341
|
-
raise ParseLocalDateTimeError(datetime=datetime) from None
|
342
|
-
try:
|
343
|
-
microsecond_use = int(microsecond)
|
340
|
+
ldt = PlainDateTime.parse_common_iso(datetime)
|
344
341
|
except ValueError:
|
345
|
-
|
346
|
-
return
|
347
|
-
year=int(year),
|
348
|
-
month=int(month),
|
349
|
-
day=int(day),
|
350
|
-
hour=int(hour),
|
351
|
-
minute=int(minute),
|
352
|
-
second=int(second),
|
353
|
-
microsecond=microsecond_use,
|
354
|
-
tzinfo=UTC,
|
355
|
-
).replace(tzinfo=None)
|
342
|
+
raise ParsePlainDateTimeError(datetime=datetime) from None
|
343
|
+
return ldt.py_datetime()
|
356
344
|
|
357
345
|
|
358
346
|
@dataclass(kw_only=True, slots=True)
|
359
|
-
class
|
347
|
+
class ParsePlainDateTimeError(Exception):
|
360
348
|
datetime: str
|
361
349
|
|
362
350
|
@override
|
363
351
|
def __str__(self) -> str:
|
364
|
-
return f"Unable to parse
|
352
|
+
return f"Unable to parse plain datetime; got {self.datetime!r}"
|
365
353
|
|
366
354
|
|
367
355
|
##
|
@@ -435,39 +423,13 @@ class _ParseTimedeltaNanosecondError(ParseTimedeltaError):
|
|
435
423
|
##
|
436
424
|
|
437
425
|
|
438
|
-
_PARSE_ZONED_DATETIME_REGEX = re.compile(
|
439
|
-
r"^(\d{4})(\d{2})(\d{2})T(\d{2})(\d{2})(\d{2})\.?(\d{6})?\[([\w\+\-/]+)\]$"
|
440
|
-
)
|
441
|
-
|
442
|
-
|
443
426
|
def parse_zoned_datetime(datetime: str, /) -> dt.datetime:
|
444
427
|
"""Parse a string into a zoned datetime."""
|
445
428
|
try:
|
446
429
|
zdt = ZonedDateTime.parse_common_iso(datetime)
|
447
|
-
except ValueError:
|
448
|
-
pass
|
449
|
-
else:
|
450
|
-
return zdt.py_datetime()
|
451
|
-
try:
|
452
|
-
((year, month, day, hour, minute, second, microsecond, timezone),) = (
|
453
|
-
_PARSE_ZONED_DATETIME_REGEX.findall(datetime)
|
454
|
-
)
|
455
430
|
except ValueError:
|
456
431
|
raise ParseZonedDateTimeError(datetime=datetime) from None
|
457
|
-
|
458
|
-
microsecond_use = int(microsecond)
|
459
|
-
except ValueError: # skipif-ci-and-windows
|
460
|
-
microsecond_use = 0
|
461
|
-
return dt.datetime( # skipif-ci-and-windows
|
462
|
-
year=int(year),
|
463
|
-
month=int(month),
|
464
|
-
day=int(day),
|
465
|
-
hour=int(hour),
|
466
|
-
minute=int(minute),
|
467
|
-
second=int(second),
|
468
|
-
microsecond=microsecond_use,
|
469
|
-
tzinfo=ZoneInfo(timezone),
|
470
|
-
)
|
432
|
+
return zdt.py_datetime()
|
471
433
|
|
472
434
|
|
473
435
|
@dataclass(kw_only=True, slots=True)
|
@@ -494,8 +456,8 @@ def serialize_date(date: dt.date, /) -> str:
|
|
494
456
|
def serialize_datetime(datetime: dt.datetime, /) -> str:
|
495
457
|
"""Serialize a datetime."""
|
496
458
|
try:
|
497
|
-
return
|
498
|
-
except
|
459
|
+
return serialize_plain_datetime(datetime)
|
460
|
+
except SerializePlainDateTimeError:
|
499
461
|
return serialize_zoned_datetime(datetime)
|
500
462
|
|
501
463
|
|
@@ -524,22 +486,22 @@ class SerializeDurationError(Exception):
|
|
524
486
|
##
|
525
487
|
|
526
488
|
|
527
|
-
def
|
528
|
-
"""Serialize a
|
489
|
+
def serialize_plain_datetime(datetime: dt.datetime, /) -> str:
|
490
|
+
"""Serialize a plain datetime."""
|
529
491
|
try:
|
530
|
-
|
492
|
+
pdt = PlainDateTime.from_py_datetime(datetime)
|
531
493
|
except ValueError:
|
532
|
-
raise
|
533
|
-
return
|
494
|
+
raise SerializePlainDateTimeError(datetime=datetime) from None
|
495
|
+
return pdt.format_common_iso()
|
534
496
|
|
535
497
|
|
536
498
|
@dataclass(kw_only=True, slots=True)
|
537
|
-
class
|
499
|
+
class SerializePlainDateTimeError(Exception):
|
538
500
|
datetime: dt.datetime
|
539
501
|
|
540
502
|
@override
|
541
503
|
def __str__(self) -> str:
|
542
|
-
return f"Unable to serialize
|
504
|
+
return f"Unable to serialize plain datetime; got {self.datetime}"
|
543
505
|
|
544
506
|
|
545
507
|
##
|
@@ -630,43 +592,43 @@ class _ToDateTimeDeltaError(Exception):
|
|
630
592
|
__all__ = [
|
631
593
|
"MAX_SERIALIZABLE_TIMEDELTA",
|
632
594
|
"MIN_SERIALIZABLE_TIMEDELTA",
|
633
|
-
"
|
595
|
+
"CheckValidZonedDateTimeError",
|
634
596
|
"EnsureDateError",
|
635
597
|
"EnsureDateTimeError",
|
636
|
-
"
|
598
|
+
"EnsurePlainDateTimeError",
|
637
599
|
"EnsureTimeError",
|
638
600
|
"EnsureTimedeltaError",
|
639
601
|
"EnsureZonedDateTimeError",
|
640
602
|
"ParseDateError",
|
641
603
|
"ParseDateTimeError",
|
642
604
|
"ParseDurationError",
|
643
|
-
"
|
605
|
+
"ParsePlainDateTimeError",
|
644
606
|
"ParseTimeError",
|
645
607
|
"ParseTimedeltaError",
|
646
608
|
"ParseZonedDateTimeError",
|
647
609
|
"SerializeDurationError",
|
648
|
-
"
|
610
|
+
"SerializePlainDateTimeError",
|
649
611
|
"SerializeTimeDeltaError",
|
650
612
|
"SerializeZonedDateTimeError",
|
651
613
|
"check_valid_zoned_datetime",
|
652
614
|
"ensure_date",
|
653
615
|
"ensure_datetime",
|
654
616
|
"ensure_duration",
|
655
|
-
"
|
617
|
+
"ensure_plain_datetime",
|
656
618
|
"ensure_time",
|
657
619
|
"ensure_timedelta",
|
658
620
|
"ensure_zoned_datetime",
|
659
621
|
"parse_date",
|
660
622
|
"parse_datetime",
|
661
623
|
"parse_duration",
|
662
|
-
"
|
624
|
+
"parse_plain_datetime",
|
663
625
|
"parse_time",
|
664
626
|
"parse_timedelta",
|
665
627
|
"parse_zoned_datetime",
|
666
628
|
"serialize_date",
|
667
629
|
"serialize_datetime",
|
668
630
|
"serialize_duration",
|
669
|
-
"
|
631
|
+
"serialize_plain_datetime",
|
670
632
|
"serialize_time",
|
671
633
|
"serialize_timedelta",
|
672
634
|
"serialize_zoned_datetime",
|
utilities/zoneinfo.py
CHANGED
@@ -32,7 +32,7 @@ def ensure_time_zone(obj: TimeZoneLike, /) -> ZoneInfo:
|
|
32
32
|
raise _EnsureTimeZoneInvalidTZInfoError(time_zone=obj)
|
33
33
|
case dt.datetime() as datetime:
|
34
34
|
if datetime.tzinfo is None:
|
35
|
-
raise
|
35
|
+
raise _EnsureTimeZonePlainDateTimeError(datetime=datetime)
|
36
36
|
return ensure_time_zone(datetime.tzinfo)
|
37
37
|
case _ as never:
|
38
38
|
assert_never(never)
|
@@ -52,12 +52,12 @@ class _EnsureTimeZoneInvalidTZInfoError(EnsureTimeZoneError):
|
|
52
52
|
|
53
53
|
|
54
54
|
@dataclass(kw_only=True, slots=True)
|
55
|
-
class
|
55
|
+
class _EnsureTimeZonePlainDateTimeError(EnsureTimeZoneError):
|
56
56
|
datetime: dt.datetime
|
57
57
|
|
58
58
|
@override
|
59
59
|
def __str__(self) -> str:
|
60
|
-
return f"
|
60
|
+
return f"Plain datetime: {self.datetime}"
|
61
61
|
|
62
62
|
|
63
63
|
##
|
File without changes
|
File without changes
|