dycw-utilities 0.136.8__py3-none-any.whl → 0.136.10__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.136.8.dist-info → dycw_utilities-0.136.10.dist-info}/METADATA +2 -2
- {dycw_utilities-0.136.8.dist-info → dycw_utilities-0.136.10.dist-info}/RECORD +12 -12
- utilities/__init__.py +1 -1
- utilities/fpdf2.py +2 -2
- utilities/logging.py +4 -4
- utilities/period.py +45 -0
- utilities/pyinstrument.py +2 -2
- utilities/traceback.py +12 -5
- utilities/typed_settings.py +20 -2
- utilities/whenever.py +21 -5
- {dycw_utilities-0.136.8.dist-info → dycw_utilities-0.136.10.dist-info}/WHEEL +0 -0
- {dycw_utilities-0.136.8.dist-info → dycw_utilities-0.136.10.dist-info}/licenses/LICENSE +0 -0
@@ -1,13 +1,13 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: dycw-utilities
|
3
|
-
Version: 0.136.
|
3
|
+
Version: 0.136.10
|
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: atomicwrites<1.5,>=1.4.1
|
8
8
|
Requires-Dist: typing-extensions<4.15,>=4.14.0
|
9
9
|
Requires-Dist: tzlocal<5.4,>=5.3.1
|
10
|
-
Requires-Dist: whenever<0.9,>=0.8.
|
10
|
+
Requires-Dist: whenever<0.9,>=0.8.6
|
11
11
|
Provides-Extra: logging
|
12
12
|
Requires-Dist: coloredlogs<15.1,>=15.0.1; extra == 'logging'
|
13
13
|
Provides-Extra: test
|
@@ -1,4 +1,4 @@
|
|
1
|
-
utilities/__init__.py,sha256=
|
1
|
+
utilities/__init__.py,sha256=8QgSKySzcmMe0_2EO7a511YvtC4NfQTMgUzRj45icM0,61
|
2
2
|
utilities/aiolimiter.py,sha256=mD0wEiqMgwpty4XTbawFpnkkmJS6R4JRsVXFUaoitSU,628
|
3
3
|
utilities/altair.py,sha256=HeZBVUocjkrTNwwKrClppsIqgNFF-ykv05HfZSoHYno,9104
|
4
4
|
utilities/asyncio.py,sha256=dcGeKQzjLBXxKzZkVIk5oZsFXEcynVbRB9iNB5XEDZk,38526
|
@@ -16,7 +16,7 @@ utilities/enum.py,sha256=IEPMGiNJBcofGPuoGZErf4bMNSBE4SLs32nvm2r81h0,5791
|
|
16
16
|
utilities/errors.py,sha256=nC7ZYtxxDBMfrTHtT_MByBfup_wfGQFRo3eDt-0ZPe8,1045
|
17
17
|
utilities/eventkit.py,sha256=cV76NIHKDPyrhnZRuhjCXse5CQqgRGXZ7p7Gon4Mu2g,12646
|
18
18
|
utilities/fastapi.py,sha256=E8T2J1-N_RbpkN4czthU6NPIxAZDzxy-k_WGJaxeJ48,2671
|
19
|
-
utilities/fpdf2.py,sha256=
|
19
|
+
utilities/fpdf2.py,sha256=ztFZeigIS6sMZj7xeC_sIHdd7szrub4V7EBHxH7j09E,1877
|
20
20
|
utilities/functions.py,sha256=qefAfW0zz7OEiRuBtKF-3tI3NaufcwAULRIFv24gZ2Q,28533
|
21
21
|
utilities/functools.py,sha256=I00ru2gQPakZw2SHVeKIKXfTv741655s6HI0lUoE0D4,1552
|
22
22
|
utilities/getpass.py,sha256=DfN5UgMAtFCqS3dSfFHUfqIMZX2shXvwphOz_6J6f6A,103
|
@@ -31,7 +31,7 @@ utilities/iterables.py,sha256=wlcm0PS2fKG-H0r0k367NOLrryMbfXLlwzUeAmBSvv8,43392
|
|
31
31
|
utilities/jupyter.py,sha256=ft5JA7fBxXKzP-L9W8f2-wbF0QeYc_2uLQNFDVk4Z-M,2917
|
32
32
|
utilities/libcst.py,sha256=XTT8cCYAYfI9ZIdxjiTCqbF45cN-viDNDa7GE5mR2T4,5615
|
33
33
|
utilities/lightweight_charts.py,sha256=JrkrAZMo6JID2Eoc9QCc05Y_pK4l2zsApIhmii1z2Ig,2764
|
34
|
-
utilities/logging.py,sha256=
|
34
|
+
utilities/logging.py,sha256=trxiM6pLmYVyHs6ELlkVDZrlYgdMKfwH5WQnbNp93aY,17871
|
35
35
|
utilities/luigi.py,sha256=wK7cB3y8NXeSa8d6r_yTKRmjMguNmIPmy52yg10vPaI,4774
|
36
36
|
utilities/math.py,sha256=_6vrDyjtaqE_OFE-F2DNWrDG_J_kMl3nFAJsok9v_bY,26862
|
37
37
|
utilities/memory_profiler.py,sha256=XzN56jDCa5aqXS_DxEjb_K4L6aIWh_5zyKi6OhcIxw0,853
|
@@ -44,7 +44,7 @@ utilities/orjson.py,sha256=y5ynSGhQjX7vikfvsHh_AklLnH7gjvsSkIC3h5tnx98,36474
|
|
44
44
|
utilities/os.py,sha256=yMNAKMyY8oFgQ1yN3TQYnwa5-A_FXz4tCDbhIctQHSs,3736
|
45
45
|
utilities/parse.py,sha256=bCZW1bBfXM2j-yLGq0TGUshOnbL8V-U8amGu_OZTE_I,17907
|
46
46
|
utilities/pathlib.py,sha256=jCFPZm4rBKylEva9wDVTwQlTTVKMepu92WrTpoGa438,3248
|
47
|
-
utilities/period.py,sha256=
|
47
|
+
utilities/period.py,sha256=6jEff_qAiE7xdFaQ1DnKgNf10D2wHhzt7hQXCBoKlgc,6842
|
48
48
|
utilities/pickle.py,sha256=MBT2xZCsv0pH868IXLGKnlcqNx2IRVKYNpRcqiQQqxw,653
|
49
49
|
utilities/platform.py,sha256=5uCKRf_ij7ukJDcbnNfhY2ay9fbrpiNLRO1t2QvcwqQ,2825
|
50
50
|
utilities/polars.py,sha256=xCeB-pLkezOoQJvgxTdz2rNlaehdhek-HmDztXWn2j0,63266
|
@@ -54,7 +54,7 @@ utilities/pqdm.py,sha256=BTsYPtbKQWwX-iXF4qCkfPG7DPxIB54J989n83bXrIo,3092
|
|
54
54
|
utilities/psutil.py,sha256=0j4YxtVb8VjaaKKiHg6UEK95SUPkEcENgPtLgPJsNv0,3760
|
55
55
|
utilities/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
56
56
|
utilities/pydantic.py,sha256=CmxCi4sukeHM3JGjJ1Rbp8UAvcx4MZapLg10mFYJ-nk,1771
|
57
|
-
utilities/pyinstrument.py,sha256=
|
57
|
+
utilities/pyinstrument.py,sha256=xN4BaS9AjLJ5YT4tCmEkCGo2PDkpCvngtA0dQ1INvSo,875
|
58
58
|
utilities/pytest.py,sha256=vv5ZpePZS6pBxl5jY3XQR5SnAhgd4f0sSMyRsvHWg60,8086
|
59
59
|
utilities/pytest_regressions.py,sha256=YI55B7EtLjhz7zPJZ6NK9bWrxrKCKabWZJe1cwcbA5o,5082
|
60
60
|
utilities/python_dotenv.py,sha256=dYooRYwqrvhSoZWuiVbCiKUWiS-M5b5yv2zDWGYPEvI,3209
|
@@ -76,8 +76,8 @@ utilities/tempfile.py,sha256=VqmZJAhTJ1OaVywFzk5eqROV8iJbW9XQ_QYAV0bpdRo,1384
|
|
76
76
|
utilities/text.py,sha256=ymBFlP_cA8OgNnZRVNs7FAh7OG8HxE6YkiLEMZv5g_A,11297
|
77
77
|
utilities/threading.py,sha256=GvBOp4CyhHfN90wGXZuA2VKe9fGzMaEa7oCl4f3nnPU,1009
|
78
78
|
utilities/timer.py,sha256=oXfTii6ymu57niP0BDGZjFD55LEHi2a19kqZKiTgaFQ,2588
|
79
|
-
utilities/traceback.py,sha256=
|
80
|
-
utilities/typed_settings.py,sha256=
|
79
|
+
utilities/traceback.py,sha256=13cKPGaJAQyK7yzxU2qsiXWzvHm3qPyEBzeizL6r7AM,8887
|
80
|
+
utilities/typed_settings.py,sha256=cZqA2IjG1erF1SUZFSsjIHmZX7BP5iIfPd6CixHllA0,4367
|
81
81
|
utilities/types.py,sha256=98pwEfkBikg6UUrshNJZgc8l97FGBbi0twIsqVt-KNA,17247
|
82
82
|
utilities/typing.py,sha256=Z-_XDaWyT_6wIo3qfNK-hvRlzxP2Jxa9PgXzm5rDYRA,13790
|
83
83
|
utilities/tzdata.py,sha256=fgNVj66yUbCSI_-vrRVzSD3gtf-L_8IEJEPjP_Jel5Y,266
|
@@ -85,10 +85,10 @@ utilities/tzlocal.py,sha256=KyCXEgCTjqGFx-389JdTuhMRUaT06U1RCMdWoED-qro,728
|
|
85
85
|
utilities/uuid.py,sha256=32p7DGHGM2Btx6PcBvCZvERSWbpupMXqx6FppPoSoTU,612
|
86
86
|
utilities/version.py,sha256=ufhJMmI6KPs1-3wBI71aj5wCukd3sP_m11usLe88DNA,5117
|
87
87
|
utilities/warnings.py,sha256=un1LvHv70PU-LLv8RxPVmugTzDJkkGXRMZTE2-fTQHw,1771
|
88
|
-
utilities/whenever.py,sha256=
|
88
|
+
utilities/whenever.py,sha256=hDk60UneSU29rpu7Q-UCM61ptcNqkhso5hoBFAvUk6M,23860
|
89
89
|
utilities/zipfile.py,sha256=24lQc9ATcJxHXBPc_tBDiJk48pWyRrlxO2fIsFxU0A8,699
|
90
90
|
utilities/zoneinfo.py,sha256=oEH-nL3t4h9uawyZqWDtNtDAl6M-CLpLYGI_nI6DulM,1971
|
91
|
-
dycw_utilities-0.136.
|
92
|
-
dycw_utilities-0.136.
|
93
|
-
dycw_utilities-0.136.
|
94
|
-
dycw_utilities-0.136.
|
91
|
+
dycw_utilities-0.136.10.dist-info/METADATA,sha256=hm82pnqhQ2zMisMtl9dRwyCvpNuS-DNp9Zwflhfu2Ok,1638
|
92
|
+
dycw_utilities-0.136.10.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
93
|
+
dycw_utilities-0.136.10.dist-info/licenses/LICENSE,sha256=gppZp16M6nSVpBbUBrNL6JuYfvKwZiKgV7XoKKsHzqo,1066
|
94
|
+
dycw_utilities-0.136.10.dist-info/RECORD,,
|
utilities/__init__.py
CHANGED
utilities/fpdf2.py
CHANGED
@@ -6,7 +6,7 @@ from typing import TYPE_CHECKING, override
|
|
6
6
|
from fpdf import FPDF
|
7
7
|
from fpdf.enums import XPos, YPos
|
8
8
|
|
9
|
-
from utilities.whenever import format_compact,
|
9
|
+
from utilities.whenever import format_compact, get_now_local
|
10
10
|
|
11
11
|
if TYPE_CHECKING:
|
12
12
|
from collections.abc import Iterator
|
@@ -47,7 +47,7 @@ def yield_pdf(*, header: str | None = None) -> Iterator[_BasePDF]:
|
|
47
47
|
def footer(self) -> None:
|
48
48
|
self.set_y(-15)
|
49
49
|
self.set_font(family="Helvetica", style="I", size=8)
|
50
|
-
page_no, now = self.page_no(), format_compact(
|
50
|
+
page_no, now = (self.page_no(), format_compact(get_now_local().to_plain()))
|
51
51
|
text = f"page {page_no}/{{}}; {now}"
|
52
52
|
_ = self.cell(
|
53
53
|
w=0,
|
utilities/logging.py
CHANGED
@@ -45,7 +45,7 @@ from utilities.re import (
|
|
45
45
|
)
|
46
46
|
from utilities.sentinel import Sentinel, sentinel
|
47
47
|
from utilities.tzlocal import LOCAL_TIME_ZONE_NAME
|
48
|
-
from utilities.whenever import WheneverLogRecord, format_compact,
|
48
|
+
from utilities.whenever import WheneverLogRecord, format_compact, get_now_local
|
49
49
|
|
50
50
|
if TYPE_CHECKING:
|
51
51
|
from collections.abc import Callable, Iterable, Mapping
|
@@ -378,7 +378,7 @@ class SizeAndTimeRotatingFileHandler(BaseRotatingHandler):
|
|
378
378
|
if not self.delay: # pragma: no cover
|
379
379
|
self.stream = self._open()
|
380
380
|
self._time_handler.rolloverAt = ( # skipif-ci-and-windows
|
381
|
-
self._time_handler.computeRollover(
|
381
|
+
self._time_handler.computeRollover(get_now_local().timestamp())
|
382
382
|
)
|
383
383
|
|
384
384
|
def _should_rollover(self, record: LogRecord, /) -> bool:
|
@@ -533,9 +533,9 @@ class _RotatingLogFile:
|
|
533
533
|
case int() as index, None, None:
|
534
534
|
tail = str(index)
|
535
535
|
case int() as index, None, ZonedDateTime() as end:
|
536
|
-
tail = f"{index}__{format_compact(end)}"
|
536
|
+
tail = f"{index}__{format_compact(end.to_plain())}"
|
537
537
|
case int() as index, ZonedDateTime() as start, ZonedDateTime() as end:
|
538
|
-
tail = f"{index}__{format_compact(start)}__{format_compact(end)}"
|
538
|
+
tail = f"{index}__{format_compact(start.to_plain())}__{format_compact(end.to_plain())}"
|
539
539
|
case _: # pragma: no cover
|
540
540
|
raise ImpossibleCaseError(
|
541
541
|
case=[f"{self.index=}", f"{self.start=}", f"{self.end=}"]
|
utilities/period.py
CHANGED
@@ -9,6 +9,7 @@ from whenever import Date, DateDelta, TimeDelta, ZonedDateTime
|
|
9
9
|
from utilities.dataclasses import replace_non_sentinel
|
10
10
|
from utilities.functions import get_class_name
|
11
11
|
from utilities.sentinel import Sentinel, sentinel
|
12
|
+
from utilities.whenever import format_compact
|
12
13
|
from utilities.zoneinfo import get_time_zone_name
|
13
14
|
|
14
15
|
if TYPE_CHECKING:
|
@@ -53,6 +54,17 @@ class DatePeriod:
|
|
53
54
|
"""The delta of the period."""
|
54
55
|
return self.end - self.start
|
55
56
|
|
57
|
+
def format_compact(self) -> str:
|
58
|
+
"""Format the period in a compact fashion."""
|
59
|
+
fc, start, end = format_compact, self.start, self.end
|
60
|
+
if self.start == self.end:
|
61
|
+
return f"{fc(start)}="
|
62
|
+
if self.start.year_month() == self.end.year_month():
|
63
|
+
return f"{fc(start)}-{fc(end, fmt='%d')}"
|
64
|
+
if self.start.year == self.end.year:
|
65
|
+
return f"{fc(start)}-{fc(end, fmt='%m%d')}"
|
66
|
+
return f"{fc(start)}-{fc(end)}"
|
67
|
+
|
56
68
|
def replace(
|
57
69
|
self, *, start: Date | Sentinel = sentinel, end: Date | Sentinel = sentinel
|
58
70
|
) -> Self:
|
@@ -101,6 +113,39 @@ class ZonedDateTimePeriod:
|
|
101
113
|
"""The duration of the period."""
|
102
114
|
return self.end - self.start
|
103
115
|
|
116
|
+
def format_compact(self) -> str:
|
117
|
+
"""Format the period in a compact fashion."""
|
118
|
+
fc, start, end = format_compact, self.start, self.end
|
119
|
+
if start == end:
|
120
|
+
if end.second != 0:
|
121
|
+
return f"{fc(start)}="
|
122
|
+
if end.minute != 0:
|
123
|
+
return f"{fc(start, fmt='%Y%m%dT%H%M')}="
|
124
|
+
return f"{fc(start, fmt='%Y%m%dT%H')}="
|
125
|
+
if start.date() == end.date():
|
126
|
+
if end.second != 0:
|
127
|
+
return f"{fc(start.to_plain())}-{fc(end, fmt='%H%M%S')}"
|
128
|
+
if end.minute != 0:
|
129
|
+
return f"{fc(start.to_plain())}-{fc(end, fmt='%H%M')}"
|
130
|
+
return f"{fc(start.to_plain())}-{fc(end, fmt='%H')}"
|
131
|
+
if start.date().year_month() == end.date().year_month():
|
132
|
+
if end.second != 0:
|
133
|
+
return f"{fc(start.to_plain())}-{fc(end, fmt='%dT%H%M%S')}"
|
134
|
+
if end.minute != 0:
|
135
|
+
return f"{fc(start.to_plain())}-{fc(end, fmt='%dT%H%M')}"
|
136
|
+
return f"{fc(start.to_plain())}-{fc(end, fmt='%dT%H')}"
|
137
|
+
if start.year == end.year:
|
138
|
+
if end.second != 0:
|
139
|
+
return f"{fc(start.to_plain())}-{fc(end, fmt='%m%dT%H%M%S')}"
|
140
|
+
if end.minute != 0:
|
141
|
+
return f"{fc(start.to_plain())}-{fc(end, fmt='%m%dT%H%M')}"
|
142
|
+
return f"{fc(start.to_plain())}-{fc(end, fmt='%m%dT%H')}"
|
143
|
+
if end.second != 0:
|
144
|
+
return f"{fc(start.to_plain())}-{fc(end)}"
|
145
|
+
if end.minute != 0:
|
146
|
+
return f"{fc(start.to_plain())}-{fc(end, fmt='%Y%m%dT%H%M')}"
|
147
|
+
return f"{fc(start.to_plain())}-{fc(end, fmt='%Y%m%dT%H')}"
|
148
|
+
|
104
149
|
def replace(
|
105
150
|
self,
|
106
151
|
*,
|
utilities/pyinstrument.py
CHANGED
@@ -8,7 +8,7 @@ from pyinstrument.profiler import Profiler
|
|
8
8
|
|
9
9
|
from utilities.atomicwrites import writer
|
10
10
|
from utilities.pathlib import get_path
|
11
|
-
from utilities.whenever import format_compact,
|
11
|
+
from utilities.whenever import format_compact, get_now_local
|
12
12
|
|
13
13
|
if TYPE_CHECKING:
|
14
14
|
from collections.abc import Iterator
|
@@ -22,7 +22,7 @@ def profile(*, path: MaybeCallablePathLike | None = Path.cwd) -> Iterator[None]:
|
|
22
22
|
with Profiler() as profiler:
|
23
23
|
yield
|
24
24
|
filename = get_path(path=path).joinpath(
|
25
|
-
f"profile__{format_compact(
|
25
|
+
f"profile__{format_compact(get_now_local().to_plain())}.html"
|
26
26
|
)
|
27
27
|
with writer(filename) as temp, temp.open(mode="w") as fh:
|
28
28
|
_ = fh.write(profiler.output_html())
|
utilities/traceback.py
CHANGED
@@ -27,7 +27,12 @@ from utilities.reprlib import (
|
|
27
27
|
yield_mapping_repr,
|
28
28
|
)
|
29
29
|
from utilities.version import get_version
|
30
|
-
from utilities.whenever import
|
30
|
+
from utilities.whenever import (
|
31
|
+
format_compact,
|
32
|
+
get_now,
|
33
|
+
get_now_local,
|
34
|
+
to_zoned_date_time,
|
35
|
+
)
|
31
36
|
|
32
37
|
if TYPE_CHECKING:
|
33
38
|
from collections.abc import Callable, Iterator, Sequence
|
@@ -89,10 +94,10 @@ def _yield_header_lines(
|
|
89
94
|
version: MaybeCallableVersionLike | None = None,
|
90
95
|
) -> Iterator[str]:
|
91
96
|
"""Yield the header lines."""
|
92
|
-
now =
|
97
|
+
now = get_now_local()
|
93
98
|
start_use = to_zoned_date_time(date_time=start)
|
94
|
-
yield f"Date/time | {format_compact(now)}"
|
95
|
-
start_str = "" if start_use is None else format_compact(start_use)
|
99
|
+
yield f"Date/time | {format_compact(now.to_plain())}"
|
100
|
+
start_str = "" if start_use is None else format_compact(start_use.to_plain())
|
96
101
|
yield f"Started | {start_str}"
|
97
102
|
delta = None if start_use is None else (now - start_use)
|
98
103
|
delta_str = "" if delta is None else delta.format_common_iso()
|
@@ -250,7 +255,9 @@ def _make_except_hook_inner(
|
|
250
255
|
_ = sys.stderr.write(f"{slim}\n") # don't 'from sys import stderr'
|
251
256
|
if path is not None:
|
252
257
|
path = (
|
253
|
-
get_path(path=path)
|
258
|
+
get_path(path=path)
|
259
|
+
.joinpath(format_compact(get_now_local().to_plain()))
|
260
|
+
.with_suffix(".txt")
|
254
261
|
)
|
255
262
|
full = format_exception_stack(
|
256
263
|
exc_val,
|
utilities/typed_settings.py
CHANGED
@@ -1,10 +1,12 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
3
|
from dataclasses import dataclass
|
4
|
+
from functools import partial
|
4
5
|
from ipaddress import IPv4Address, IPv6Address
|
6
|
+
from os import environ
|
5
7
|
from pathlib import Path
|
6
8
|
from re import search
|
7
|
-
from typing import TYPE_CHECKING, Any, override
|
9
|
+
from typing import TYPE_CHECKING, Any, assert_never, override
|
8
10
|
|
9
11
|
import typed_settings
|
10
12
|
from typed_settings import EnvLoader, FileLoader, find
|
@@ -21,6 +23,8 @@ from whenever import (
|
|
21
23
|
)
|
22
24
|
|
23
25
|
from utilities.iterables import always_iterable
|
26
|
+
from utilities.pathlib import get_path
|
27
|
+
from utilities.string import substitute_environ
|
24
28
|
from utilities.whenever import Freq
|
25
29
|
|
26
30
|
if TYPE_CHECKING:
|
@@ -29,7 +33,7 @@ if TYPE_CHECKING:
|
|
29
33
|
from typed_settings.loaders import Loader
|
30
34
|
from typed_settings.processors import Processor
|
31
35
|
|
32
|
-
from utilities.types import MaybeIterable, PathLike
|
36
|
+
from utilities.types import MaybeCallablePathLike, MaybeIterable, PathLike
|
33
37
|
|
34
38
|
|
35
39
|
##
|
@@ -53,6 +57,7 @@ class ExtendedTSConverter(TSConverter):
|
|
53
57
|
(Freq, Freq.parse),
|
54
58
|
(IPv4Address, IPv4Address),
|
55
59
|
(IPv6Address, IPv6Address),
|
60
|
+
(Path, partial(_parse_path, resolve=resolve_paths, pwd=Path.cwd())),
|
56
61
|
(PlainDateTime, PlainDateTime.parse_common_iso),
|
57
62
|
(Time, Time.parse_common_iso),
|
58
63
|
(TimeDelta, TimeDelta.parse_common_iso),
|
@@ -76,6 +81,19 @@ def _make_converter[T](
|
|
76
81
|
return hook
|
77
82
|
|
78
83
|
|
84
|
+
def _parse_path(
|
85
|
+
path: str, /, *, resolve: bool = False, pwd: MaybeCallablePathLike | None = None
|
86
|
+
) -> Path:
|
87
|
+
path = substitute_environ(path, **environ)
|
88
|
+
match resolve:
|
89
|
+
case True:
|
90
|
+
return get_path(path=pwd).joinpath(path).resolve()
|
91
|
+
case False:
|
92
|
+
return Path(path)
|
93
|
+
case _ as never:
|
94
|
+
assert_never(never)
|
95
|
+
|
96
|
+
|
79
97
|
##
|
80
98
|
|
81
99
|
_BASE_DIR: Path = Path()
|
utilities/whenever.py
CHANGED
@@ -23,6 +23,7 @@ from whenever import (
|
|
23
23
|
DateDelta,
|
24
24
|
DateTimeDelta,
|
25
25
|
PlainDateTime,
|
26
|
+
Time,
|
26
27
|
TimeDelta,
|
27
28
|
ZonedDateTime,
|
28
29
|
)
|
@@ -32,7 +33,7 @@ from utilities.platform import get_strftime
|
|
32
33
|
from utilities.re import ExtractGroupsError, extract_groups
|
33
34
|
from utilities.sentinel import Sentinel, sentinel
|
34
35
|
from utilities.types import DateTimeRoundUnit, MaybeStr
|
35
|
-
from utilities.tzlocal import LOCAL_TIME_ZONE
|
36
|
+
from utilities.tzlocal import LOCAL_TIME_ZONE
|
36
37
|
from utilities.zoneinfo import UTC, get_time_zone_name
|
37
38
|
|
38
39
|
if TYPE_CHECKING:
|
@@ -160,10 +161,25 @@ def datetime_utc(
|
|
160
161
|
##
|
161
162
|
|
162
163
|
|
163
|
-
def format_compact(
|
164
|
-
|
165
|
-
|
166
|
-
|
164
|
+
def format_compact(
|
165
|
+
obj: Date | Time | PlainDateTime | ZonedDateTime, /, *, fmt: str | None = None
|
166
|
+
) -> str:
|
167
|
+
"""Format the date/datetime in a compact fashion."""
|
168
|
+
match obj:
|
169
|
+
case Date() as date:
|
170
|
+
obj_use = date.py_date()
|
171
|
+
fmt_use = "%Y%m%d" if fmt is None else fmt
|
172
|
+
case Time() as time:
|
173
|
+
obj_use = time.py_time()
|
174
|
+
fmt_use = "%H%M%S" if fmt is None else fmt
|
175
|
+
case PlainDateTime() as datetime:
|
176
|
+
obj_use = datetime.round().py_datetime()
|
177
|
+
fmt_use = "%Y%m%dT%H%M%S" if fmt is None else fmt
|
178
|
+
case ZonedDateTime() as datetime:
|
179
|
+
return f"{format_compact(datetime.to_plain(), fmt=fmt)}[{datetime.tz}]"
|
180
|
+
case _ as never:
|
181
|
+
assert_never(never)
|
182
|
+
return obj_use.strftime(get_strftime(fmt_use))
|
167
183
|
|
168
184
|
|
169
185
|
##
|
File without changes
|
File without changes
|