dycw-utilities 0.109.2__py3-none-any.whl → 0.109.4__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.109.2.dist-info → dycw_utilities-0.109.4.dist-info}/METADATA +1 -1
- {dycw_utilities-0.109.2.dist-info → dycw_utilities-0.109.4.dist-info}/RECORD +7 -7
- utilities/__init__.py +1 -1
- utilities/parse.py +77 -22
- utilities/typing.py +9 -0
- {dycw_utilities-0.109.2.dist-info → dycw_utilities-0.109.4.dist-info}/WHEEL +0 -0
- {dycw_utilities-0.109.2.dist-info → dycw_utilities-0.109.4.dist-info}/licenses/LICENSE +0 -0
@@ -1,4 +1,4 @@
|
|
1
|
-
utilities/__init__.py,sha256=
|
1
|
+
utilities/__init__.py,sha256=TfQi7UYijWAmuZ8wsQ7kQKbgWiSQWgaXE80fBUn8qx8,60
|
2
2
|
utilities/altair.py,sha256=NSyDsm8QlkAGmsGdxVwCkHnPxt_35yJBa9Lg7bz9Ays,9054
|
3
3
|
utilities/astor.py,sha256=xuDUkjq0-b6fhtwjhbnebzbqQZAjMSHR1IIS5uOodVg,777
|
4
4
|
utilities/asyncio.py,sha256=41oQUurWMvadFK5gFnaG21hMM0Vmfn2WS6OpC0R9mas,14757
|
@@ -40,7 +40,7 @@ utilities/operator.py,sha256=0M2yZJ0PODH47ogFEnkGMBe_cfxwZR02T_92LZVZvHo,3715
|
|
40
40
|
utilities/optuna.py,sha256=loyJGWTzljgdJaoLhP09PT8Jz6o_pwBOwehY33lHkhw,1923
|
41
41
|
utilities/orjson.py,sha256=Wj5pzG_VdgoAy14a7Luhem-BgYrRtRFvvl_POiszRd0,36930
|
42
42
|
utilities/os.py,sha256=D_FyyT-6TtqiN9KSS7c9g1fnUtgxmyMtzAjmYLkk46A,3587
|
43
|
-
utilities/parse.py,sha256=
|
43
|
+
utilities/parse.py,sha256=q1A1-bsXltdAh8We5Acy-lPuVIClWTxsRXQWq5wYyKk,6382
|
44
44
|
utilities/pathlib.py,sha256=31WPMXdLIyXgYOMMl_HOI2wlo66MGSE-cgeelk-Lias,1410
|
45
45
|
utilities/period.py,sha256=ikHXsWtDLr553cfH6p9mMaiCnIAP69B7q84ckWV3HaA,10884
|
46
46
|
utilities/pickle.py,sha256=Bhvd7cZl-zQKQDFjUerqGuSKlHvnW1K2QXeU5UZibtg,657
|
@@ -75,7 +75,7 @@ utilities/threading.py,sha256=GvBOp4CyhHfN90wGXZuA2VKe9fGzMaEa7oCl4f3nnPU,1009
|
|
75
75
|
utilities/timer.py,sha256=Rkc49KSpHuC8s7vUxGO9DU55U9I6yDKnchsQqrUCVBs,4075
|
76
76
|
utilities/traceback.py,sha256=KwHPLdEbdj0fFhXo8MBfxcvem8A-VXYDwFMNJ6f0cTM,27328
|
77
77
|
utilities/types.py,sha256=QK8kgH80TJdh_vktaZHrCEk7f1f8kHiDr8dJlK8aSac,17814
|
78
|
-
utilities/typing.py,sha256=
|
78
|
+
utilities/typing.py,sha256=gLg4EbE1FX52fJ1d3ji4i08qolwu9qgWt8w_w_Y5DTk,5512
|
79
79
|
utilities/tzdata.py,sha256=2ZsPmhTVM9Ptrxb4QrWKtKOB9RiH8IOO-A1u7ULdVbg,176
|
80
80
|
utilities/tzlocal.py,sha256=42BCquGF54oIqIKe5RGziP4K8Nbm3Ey7uqcNn6m5ge8,534
|
81
81
|
utilities/uuid.py,sha256=jJTFxz-CWgltqNuzmythB7iEQ-Q1mCwPevUfKthZT3c,611
|
@@ -84,7 +84,7 @@ utilities/warnings.py,sha256=yUgjnmkCRf6QhdyAXzl7u0qQFejhQG3PrjoSwxpbHrs,1819
|
|
84
84
|
utilities/whenever.py,sha256=5x2t47VJmJRWcd_NLFy54NkB3uom-XQYxEbLtEfL1bs,17775
|
85
85
|
utilities/zipfile.py,sha256=24lQc9ATcJxHXBPc_tBDiJk48pWyRrlxO2fIsFxU0A8,699
|
86
86
|
utilities/zoneinfo.py,sha256=-DQz5a0Ikw9jfSZtL0BEQkXOMC9yGn_xiJYNCLMiqEc,1989
|
87
|
-
dycw_utilities-0.109.
|
88
|
-
dycw_utilities-0.109.
|
89
|
-
dycw_utilities-0.109.
|
90
|
-
dycw_utilities-0.109.
|
87
|
+
dycw_utilities-0.109.4.dist-info/METADATA,sha256=-fU_tSw6cCv59Fg6s0I0pUlV3YzXeuq15kfirsKUmik,13004
|
88
|
+
dycw_utilities-0.109.4.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
89
|
+
dycw_utilities-0.109.4.dist-info/licenses/LICENSE,sha256=gppZp16M6nSVpBbUBrNL6JuYfvKwZiKgV7XoKKsHzqo,1066
|
90
|
+
dycw_utilities-0.109.4.dist-info/RECORD,,
|
utilities/__init__.py
CHANGED
utilities/parse.py
CHANGED
@@ -5,30 +5,44 @@ from contextlib import suppress
|
|
5
5
|
from dataclasses import dataclass
|
6
6
|
from enum import Enum
|
7
7
|
from pathlib import Path
|
8
|
+
from re import DOTALL
|
8
9
|
from types import NoneType
|
9
|
-
from typing import Any, override
|
10
|
+
from typing import TYPE_CHECKING, Any, TypeVar, override
|
10
11
|
|
11
12
|
from utilities.datetime import is_subclass_date_not_datetime
|
12
13
|
from utilities.enum import ParseEnumError, parse_enum
|
13
14
|
from utilities.functions import is_subclass_int_not_bool
|
14
|
-
from utilities.iterables import one, one_str
|
15
|
+
from utilities.iterables import OneEmptyError, OneNonUniqueError, one, one_str
|
16
|
+
from utilities.re import ExtractGroupError, extract_group
|
15
17
|
from utilities.sentinel import ParseSentinelError, Sentinel, parse_sentinel
|
16
18
|
from utilities.text import ParseBoolError, ParseNoneError, parse_bool, parse_none
|
17
|
-
from utilities.typing import get_args, is_literal_type, is_optional_type
|
19
|
+
from utilities.typing import get_args, is_literal_type, is_optional_type, is_tuple_type
|
18
20
|
from utilities.version import ParseVersionError, Version, parse_version
|
19
21
|
|
22
|
+
if TYPE_CHECKING:
|
23
|
+
from collections.abc import Callable, Mapping
|
24
|
+
|
25
|
+
|
26
|
+
_T = TypeVar("_T")
|
27
|
+
|
20
28
|
|
21
29
|
def parse_text(
|
22
|
-
obj: Any,
|
30
|
+
obj: Any,
|
31
|
+
text: str,
|
32
|
+
/,
|
33
|
+
*,
|
34
|
+
case_sensitive: bool = False,
|
35
|
+
head: bool = False,
|
36
|
+
extra: Mapping[type[_T], Callable[[str], _T]] | None = None,
|
23
37
|
) -> Any:
|
24
38
|
"""Parse text."""
|
25
39
|
if obj is None:
|
26
40
|
try:
|
27
41
|
return parse_none(text)
|
28
42
|
except ParseNoneError:
|
29
|
-
raise
|
43
|
+
raise _ParseTextParseError(obj=obj, text=text) from None
|
30
44
|
if isinstance(obj, type):
|
31
|
-
return _parse_text_type(obj, text, case_sensitive=case_sensitive)
|
45
|
+
return _parse_text_type(obj, text, case_sensitive=case_sensitive, extra=extra)
|
32
46
|
if is_literal_type(obj):
|
33
47
|
return one_str(get_args(obj), text, head=head, case_sensitive=case_sensitive)
|
34
48
|
if is_optional_type(obj):
|
@@ -40,83 +54,111 @@ def parse_text(
|
|
40
54
|
):
|
41
55
|
try:
|
42
56
|
return _parse_text_type(inner, text, case_sensitive=case_sensitive)
|
43
|
-
except
|
44
|
-
raise
|
45
|
-
|
57
|
+
except _ParseTextParseError:
|
58
|
+
raise _ParseTextParseError(obj=obj, text=text) from None
|
59
|
+
if is_tuple_type(obj):
|
60
|
+
args = get_args(obj)
|
61
|
+
try:
|
62
|
+
texts = extract_group(r"^\((.*)\)$", text, flags=DOTALL).split(", ")
|
63
|
+
except ExtractGroupError:
|
64
|
+
raise _ParseTextParseError(obj=obj, text=text) from None
|
65
|
+
if len(args) != len(texts):
|
66
|
+
raise _ParseTextParseError(obj=obj, text=text)
|
67
|
+
return tuple(
|
68
|
+
parse_text(arg, text, case_sensitive=case_sensitive, head=head)
|
69
|
+
for arg, text in zip(args, texts, strict=True)
|
70
|
+
)
|
71
|
+
raise _ParseTextParseError(obj=obj, text=text) from None
|
46
72
|
|
47
73
|
|
48
74
|
def _parse_text_type(
|
49
|
-
cls: type[Any],
|
75
|
+
cls: type[Any],
|
76
|
+
text: str,
|
77
|
+
/,
|
78
|
+
*,
|
79
|
+
case_sensitive: bool = False,
|
80
|
+
extra: Mapping[type[_T], Callable[[str], _T]] | None = None,
|
50
81
|
) -> Any:
|
51
82
|
"""Parse text."""
|
52
83
|
if issubclass(cls, NoneType):
|
53
84
|
try:
|
54
85
|
return parse_none(text)
|
55
86
|
except ParseNoneError:
|
56
|
-
raise
|
87
|
+
raise _ParseTextParseError(obj=cls, text=text) from None
|
57
88
|
if issubclass(cls, str):
|
58
89
|
return text
|
59
90
|
if issubclass(cls, bool):
|
60
91
|
try:
|
61
92
|
return parse_bool(text)
|
62
93
|
except ParseBoolError:
|
63
|
-
raise
|
94
|
+
raise _ParseTextParseError(obj=cls, text=text) from None
|
64
95
|
if is_subclass_int_not_bool(cls):
|
65
96
|
try:
|
66
97
|
return int(text)
|
67
98
|
except ValueError:
|
68
|
-
raise
|
99
|
+
raise _ParseTextParseError(obj=cls, text=text) from None
|
69
100
|
if issubclass(cls, float):
|
70
101
|
try:
|
71
102
|
return float(text)
|
72
103
|
except ValueError:
|
73
|
-
raise
|
104
|
+
raise _ParseTextParseError(obj=cls, text=text) from None
|
74
105
|
if issubclass(cls, Enum):
|
75
106
|
try:
|
76
107
|
return parse_enum(text, cls, case_sensitive=case_sensitive)
|
77
108
|
except ParseEnumError:
|
78
|
-
raise
|
109
|
+
raise _ParseTextParseError(obj=cls, text=text) from None
|
79
110
|
if issubclass(cls, Path):
|
80
111
|
return Path(text).expanduser()
|
81
112
|
if issubclass(cls, Sentinel):
|
82
113
|
try:
|
83
114
|
return parse_sentinel(text)
|
84
115
|
except ParseSentinelError:
|
85
|
-
raise
|
116
|
+
raise _ParseTextParseError(obj=cls, text=text) from None
|
86
117
|
if issubclass(cls, Version):
|
87
118
|
try:
|
88
119
|
return parse_version(text)
|
89
120
|
except ParseVersionError:
|
90
|
-
raise
|
121
|
+
raise _ParseTextParseError(obj=cls, text=text) from None
|
91
122
|
if is_subclass_date_not_datetime(cls):
|
92
123
|
from utilities.whenever import ParseDateError, parse_date
|
93
124
|
|
94
125
|
try:
|
95
126
|
return parse_date(text)
|
96
127
|
except ParseDateError:
|
97
|
-
raise
|
128
|
+
raise _ParseTextParseError(obj=cls, text=text) from None
|
98
129
|
if issubclass(cls, dt.datetime):
|
99
130
|
from utilities.whenever import ParseDateTimeError, parse_datetime
|
100
131
|
|
101
132
|
try:
|
102
133
|
return parse_datetime(text)
|
103
134
|
except ParseDateTimeError:
|
104
|
-
raise
|
135
|
+
raise _ParseTextParseError(obj=cls, text=text) from None
|
105
136
|
if issubclass(cls, dt.time):
|
106
137
|
from utilities.whenever import ParseTimeError, parse_time
|
107
138
|
|
108
139
|
try:
|
109
140
|
return parse_time(text)
|
110
141
|
except ParseTimeError:
|
111
|
-
raise
|
142
|
+
raise _ParseTextParseError(obj=cls, text=text) from None
|
112
143
|
if issubclass(cls, dt.timedelta):
|
113
144
|
from utilities.whenever import ParseTimedeltaError, parse_timedelta
|
114
145
|
|
115
146
|
try:
|
116
147
|
return parse_timedelta(text)
|
117
148
|
except ParseTimedeltaError:
|
118
|
-
raise
|
119
|
-
|
149
|
+
raise _ParseTextParseError(obj=cls, text=text) from None
|
150
|
+
if extra is not None:
|
151
|
+
try:
|
152
|
+
parser = one(p for c, p in extra.items() if issubclass(cls, c))
|
153
|
+
except OneEmptyError:
|
154
|
+
pass
|
155
|
+
except OneNonUniqueError as error:
|
156
|
+
raise _ParseTextExtraNonUniqueError(
|
157
|
+
obj=cls, text=text, first=error.first, second=error.second
|
158
|
+
) from None
|
159
|
+
else:
|
160
|
+
return parser(text)
|
161
|
+
raise _ParseTextParseError(obj=cls, text=text) from None
|
120
162
|
|
121
163
|
|
122
164
|
@dataclass
|
@@ -124,6 +166,19 @@ class ParseTextError(Exception):
|
|
124
166
|
obj: Any
|
125
167
|
text: str
|
126
168
|
|
169
|
+
|
170
|
+
@dataclass
|
171
|
+
class _ParseTextParseError(ParseTextError):
|
127
172
|
@override
|
128
173
|
def __str__(self) -> str:
|
129
174
|
return f"Unable to parse {self.obj!r}; got {self.text!r}"
|
175
|
+
|
176
|
+
|
177
|
+
@dataclass
|
178
|
+
class _ParseTextExtraNonUniqueError(ParseTextError):
|
179
|
+
first: type[Any]
|
180
|
+
second: type[Any]
|
181
|
+
|
182
|
+
@override
|
183
|
+
def __str__(self) -> str:
|
184
|
+
return f"Unable to parse {self.obj!r} since `extra` must contain exactly one parent class; got {self.first!r}, {self.second!r} and perhaps more"
|
utilities/typing.py
CHANGED
@@ -182,6 +182,14 @@ def is_set_type(obj: Any, /) -> bool:
|
|
182
182
|
##
|
183
183
|
|
184
184
|
|
185
|
+
def is_tuple_type(obj: Any, /) -> bool:
|
186
|
+
"""Check if an object is a tuple type annotation."""
|
187
|
+
return _is_annotation_of_type(obj, tuple)
|
188
|
+
|
189
|
+
|
190
|
+
##
|
191
|
+
|
192
|
+
|
185
193
|
def is_union_type(obj: Any, /) -> bool:
|
186
194
|
"""Check if an object is a union type annotation."""
|
187
195
|
is_old_union = _is_annotation_of_type(obj, Union) # pyright: ignore[reportDeprecated]
|
@@ -212,5 +220,6 @@ __all__ = [
|
|
212
220
|
"is_optional_type",
|
213
221
|
"is_sequence_type",
|
214
222
|
"is_set_type",
|
223
|
+
"is_tuple_type",
|
215
224
|
"is_union_type",
|
216
225
|
]
|
File without changes
|
File without changes
|