dycw-utilities 0.108.1__py3-none-any.whl → 0.108.2__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.108.1.dist-info → dycw_utilities-0.108.2.dist-info}/METADATA +1 -1
- {dycw_utilities-0.108.1.dist-info → dycw_utilities-0.108.2.dist-info}/RECORD +8 -7
- utilities/__init__.py +1 -1
- utilities/parse.py +129 -0
- utilities/sentinel.py +28 -1
- utilities/text.py +22 -1
- {dycw_utilities-0.108.1.dist-info → dycw_utilities-0.108.2.dist-info}/WHEEL +0 -0
- {dycw_utilities-0.108.1.dist-info → dycw_utilities-0.108.2.dist-info}/licenses/LICENSE +0 -0
@@ -1,4 +1,4 @@
|
|
1
|
-
utilities/__init__.py,sha256=
|
1
|
+
utilities/__init__.py,sha256=cA1_Gx_WFoPXFOqGWzIcljSCQWUSLDE4oIIYB9493-g,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,6 +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=DW5pOpMyrR5Q8caQYly9AqRPazDBqrWv5GRWfULqka4,36291
|
42
42
|
utilities/os.py,sha256=D_FyyT-6TtqiN9KSS7c9g1fnUtgxmyMtzAjmYLkk46A,3587
|
43
|
+
utilities/parse.py,sha256=vKVWIqR5JykQzPSnMHQr7_h43M6TwfYEnPmjmbgSA-o,4585
|
43
44
|
utilities/pathlib.py,sha256=31WPMXdLIyXgYOMMl_HOI2wlo66MGSE-cgeelk-Lias,1410
|
44
45
|
utilities/period.py,sha256=ikHXsWtDLr553cfH6p9mMaiCnIAP69B7q84ckWV3HaA,10884
|
45
46
|
utilities/pickle.py,sha256=Bhvd7cZl-zQKQDFjUerqGuSKlHvnW1K2QXeU5UZibtg,657
|
@@ -59,7 +60,7 @@ utilities/redis.py,sha256=CsDQqc9V6ASLzLQwtbQXZQEndyG9pJiCOhPlPeszt7Y,21203
|
|
59
60
|
utilities/reprlib.py,sha256=Re9bk3n-kC__9DxQmRlevqFA86pE6TtVfWjUgpbVOv0,1849
|
60
61
|
utilities/rich.py,sha256=t50MwwVBsoOLxzmeVFSVpjno4OW6Ufum32skXbV8-Bs,1911
|
61
62
|
utilities/scipy.py,sha256=X6ROnHwiUhAmPhM0jkfEh0-Fd9iRvwiqtCQMOLmOQF8,945
|
62
|
-
utilities/sentinel.py,sha256=
|
63
|
+
utilities/sentinel.py,sha256=0X1GWWcnPxGCo7wDgVTOfhU5iKlXdvVZudlMM0iezDw,1246
|
63
64
|
utilities/shelve.py,sha256=HZsMwK4tcIfg3sh0gApx4-yjQnrY4o3V3ZRimvRhoW0,738
|
64
65
|
utilities/slack_sdk.py,sha256=SeDNMh24IPiEBWoGMdgvrflUaFa9TGlTS03H9-NKaQw,4132
|
65
66
|
utilities/socket.py,sha256=K77vfREvzoVTrpYKo6MZakol0EYu2q1sWJnnZqL0So0,118
|
@@ -69,7 +70,7 @@ utilities/streamlit.py,sha256=U9PJBaKP1IdSykKhPZhIzSPTZsmLsnwbEPZWzNhJPKk,2955
|
|
69
70
|
utilities/sys.py,sha256=h0Xr7Vj86wNalvwJVP1wj5Y0kD_VWm1vzuXZ_jw94mE,2743
|
70
71
|
utilities/tempfile.py,sha256=VqmZJAhTJ1OaVywFzk5eqROV8iJbW9XQ_QYAV0bpdRo,1384
|
71
72
|
utilities/tenacity.py,sha256=1PUvODiBVgeqIh7G5TRt5WWMSqjLYkEqP53itT97WQc,4914
|
72
|
-
utilities/text.py,sha256=
|
73
|
+
utilities/text.py,sha256=X_EjRQeV_PsG3oP7OiGYIyXGKWqciTnSwoKhM2tsy6M,3120
|
73
74
|
utilities/threading.py,sha256=GvBOp4CyhHfN90wGXZuA2VKe9fGzMaEa7oCl4f3nnPU,1009
|
74
75
|
utilities/timer.py,sha256=Rkc49KSpHuC8s7vUxGO9DU55U9I6yDKnchsQqrUCVBs,4075
|
75
76
|
utilities/traceback.py,sha256=KwHPLdEbdj0fFhXo8MBfxcvem8A-VXYDwFMNJ6f0cTM,27328
|
@@ -83,7 +84,7 @@ utilities/warnings.py,sha256=yUgjnmkCRf6QhdyAXzl7u0qQFejhQG3PrjoSwxpbHrs,1819
|
|
83
84
|
utilities/whenever.py,sha256=5x2t47VJmJRWcd_NLFy54NkB3uom-XQYxEbLtEfL1bs,17775
|
84
85
|
utilities/zipfile.py,sha256=24lQc9ATcJxHXBPc_tBDiJk48pWyRrlxO2fIsFxU0A8,699
|
85
86
|
utilities/zoneinfo.py,sha256=-DQz5a0Ikw9jfSZtL0BEQkXOMC9yGn_xiJYNCLMiqEc,1989
|
86
|
-
dycw_utilities-0.108.
|
87
|
-
dycw_utilities-0.108.
|
88
|
-
dycw_utilities-0.108.
|
89
|
-
dycw_utilities-0.108.
|
87
|
+
dycw_utilities-0.108.2.dist-info/METADATA,sha256=N4v4D-Slw7bPRUT5KdnuEIJnUoDQVx3pTRFXkQ8kNp4,13004
|
88
|
+
dycw_utilities-0.108.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
89
|
+
dycw_utilities-0.108.2.dist-info/licenses/LICENSE,sha256=gppZp16M6nSVpBbUBrNL6JuYfvKwZiKgV7XoKKsHzqo,1066
|
90
|
+
dycw_utilities-0.108.2.dist-info/RECORD,,
|
utilities/__init__.py
CHANGED
utilities/parse.py
ADDED
@@ -0,0 +1,129 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
import datetime as dt
|
4
|
+
from contextlib import suppress
|
5
|
+
from dataclasses import dataclass
|
6
|
+
from enum import Enum
|
7
|
+
from pathlib import Path
|
8
|
+
from types import NoneType
|
9
|
+
from typing import Any, get_args, override
|
10
|
+
|
11
|
+
from utilities.datetime import is_subclass_date_not_datetime
|
12
|
+
from utilities.enum import ParseEnumError, parse_enum
|
13
|
+
from utilities.functions import is_subclass_int_not_bool
|
14
|
+
from utilities.iterables import one, one_str
|
15
|
+
from utilities.sentinel import ParseSentinelError, Sentinel, parse_sentinel
|
16
|
+
from utilities.text import ParseBoolError, ParseNoneError, parse_bool, parse_none
|
17
|
+
from utilities.typing import is_literal_type, is_optional_type
|
18
|
+
from utilities.version import ParseVersionError, Version, parse_version
|
19
|
+
|
20
|
+
|
21
|
+
def parse_text(
|
22
|
+
obj: Any, text: str, /, *, case_sensitive: bool = False, head: bool = False
|
23
|
+
) -> Any:
|
24
|
+
"""Parse text."""
|
25
|
+
if obj is None:
|
26
|
+
try:
|
27
|
+
return parse_none(text)
|
28
|
+
except ParseNoneError:
|
29
|
+
raise ParseTextError(obj=obj, text=text) from None
|
30
|
+
if isinstance(obj, type):
|
31
|
+
return _parse_text_type(obj, text, case_sensitive=case_sensitive)
|
32
|
+
if is_literal_type(obj):
|
33
|
+
return one_str(get_args(obj), text, head=head, case_sensitive=case_sensitive)
|
34
|
+
if is_optional_type(obj):
|
35
|
+
with suppress(ParseNoneError):
|
36
|
+
return parse_none(text)
|
37
|
+
inner = one(arg for arg in get_args(obj) if arg is not NoneType)
|
38
|
+
if isinstance(
|
39
|
+
inner := one(arg for arg in get_args(obj) if arg is not NoneType), type
|
40
|
+
):
|
41
|
+
try:
|
42
|
+
return _parse_text_type(inner, text, case_sensitive=case_sensitive)
|
43
|
+
except ParseTextError:
|
44
|
+
raise ParseTextError(obj=obj, text=text) from None
|
45
|
+
raise ParseTextError(obj=obj, text=text) from None
|
46
|
+
|
47
|
+
|
48
|
+
def _parse_text_type(
|
49
|
+
cls: type[Any], text: str, /, *, case_sensitive: bool = False
|
50
|
+
) -> Any:
|
51
|
+
"""Parse text."""
|
52
|
+
if issubclass(cls, NoneType):
|
53
|
+
try:
|
54
|
+
return parse_none(text)
|
55
|
+
except ParseNoneError:
|
56
|
+
raise ParseTextError(obj=cls, text=text) from None
|
57
|
+
if issubclass(cls, str):
|
58
|
+
return text
|
59
|
+
if issubclass(cls, bool):
|
60
|
+
try:
|
61
|
+
return parse_bool(text)
|
62
|
+
except ParseBoolError:
|
63
|
+
raise ParseTextError(obj=cls, text=text) from None
|
64
|
+
if is_subclass_int_not_bool(cls):
|
65
|
+
try:
|
66
|
+
return int(text)
|
67
|
+
except ValueError:
|
68
|
+
raise ParseTextError(obj=cls, text=text) from None
|
69
|
+
if issubclass(cls, float):
|
70
|
+
try:
|
71
|
+
return float(text)
|
72
|
+
except ValueError:
|
73
|
+
raise ParseTextError(obj=cls, text=text) from None
|
74
|
+
if issubclass(cls, Enum):
|
75
|
+
try:
|
76
|
+
return parse_enum(text, cls, case_sensitive=case_sensitive)
|
77
|
+
except ParseEnumError:
|
78
|
+
raise ParseTextError(obj=cls, text=text) from None
|
79
|
+
if issubclass(cls, Path):
|
80
|
+
return Path(text).expanduser()
|
81
|
+
if issubclass(cls, Sentinel):
|
82
|
+
try:
|
83
|
+
return parse_sentinel(text)
|
84
|
+
except ParseSentinelError:
|
85
|
+
raise ParseTextError(obj=cls, text=text) from None
|
86
|
+
if issubclass(cls, Version):
|
87
|
+
try:
|
88
|
+
return parse_version(text)
|
89
|
+
except ParseVersionError:
|
90
|
+
raise ParseTextError(obj=cls, text=text) from None
|
91
|
+
if is_subclass_date_not_datetime(cls):
|
92
|
+
from utilities.whenever import ParseDateError, parse_date
|
93
|
+
|
94
|
+
try:
|
95
|
+
return parse_date(text)
|
96
|
+
except ParseDateError:
|
97
|
+
raise ParseTextError(obj=cls, text=text) from None
|
98
|
+
if issubclass(cls, dt.datetime):
|
99
|
+
from utilities.whenever import ParseDateTimeError, parse_datetime
|
100
|
+
|
101
|
+
try:
|
102
|
+
return parse_datetime(text)
|
103
|
+
except ParseDateTimeError:
|
104
|
+
raise ParseTextError(obj=cls, text=text) from None
|
105
|
+
if issubclass(cls, dt.time):
|
106
|
+
from utilities.whenever import ParseTimeError, parse_time
|
107
|
+
|
108
|
+
try:
|
109
|
+
return parse_time(text)
|
110
|
+
except ParseTimeError:
|
111
|
+
raise ParseTextError(obj=cls, text=text) from None
|
112
|
+
if issubclass(cls, dt.timedelta):
|
113
|
+
from utilities.whenever import ParseTimedeltaError, parse_timedelta
|
114
|
+
|
115
|
+
try:
|
116
|
+
return parse_timedelta(text)
|
117
|
+
except ParseTimedeltaError:
|
118
|
+
raise ParseTextError(obj=cls, text=text) from None
|
119
|
+
raise ParseTextError(obj=cls, text=text) from None
|
120
|
+
|
121
|
+
|
122
|
+
@dataclass
|
123
|
+
class ParseTextError(Exception):
|
124
|
+
obj: Any
|
125
|
+
text: str
|
126
|
+
|
127
|
+
@override
|
128
|
+
def __str__(self) -> str:
|
129
|
+
return f"Unable to parse {self.obj!r}; got {self.text!r}"
|
utilities/sentinel.py
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
|
+
from dataclasses import dataclass
|
4
|
+
from re import IGNORECASE, search
|
3
5
|
from typing import Any, override
|
4
6
|
|
5
7
|
|
@@ -33,4 +35,29 @@ class Sentinel(metaclass=_Meta):
|
|
33
35
|
sentinel = Sentinel()
|
34
36
|
|
35
37
|
|
36
|
-
|
38
|
+
##
|
39
|
+
|
40
|
+
|
41
|
+
def parse_sentinel(text: str, /) -> Sentinel:
|
42
|
+
"""Parse text into the Sentinel value."""
|
43
|
+
if text == "" or search("Sentinel", text, flags=IGNORECASE):
|
44
|
+
return sentinel
|
45
|
+
raise ParseSentinelError(text=text)
|
46
|
+
|
47
|
+
|
48
|
+
@dataclass(kw_only=True, slots=True)
|
49
|
+
class ParseSentinelError(Exception):
|
50
|
+
text: str
|
51
|
+
|
52
|
+
@override
|
53
|
+
def __str__(self) -> str:
|
54
|
+
return f"Unable to parse sentinel value; got {self.text!r}"
|
55
|
+
|
56
|
+
|
57
|
+
__all__ = [
|
58
|
+
"SENTINEL_REPR",
|
59
|
+
"ParseSentinelError",
|
60
|
+
"Sentinel",
|
61
|
+
"parse_sentinel",
|
62
|
+
"sentinel",
|
63
|
+
]
|
utilities/text.py
CHANGED
@@ -45,7 +45,26 @@ class ParseBoolError(Exception):
|
|
45
45
|
|
46
46
|
@override
|
47
47
|
def __str__(self) -> str:
|
48
|
-
return f"Unable to parse {self.text!r}
|
48
|
+
return f"Unable to parse boolean value; got {self.text!r}"
|
49
|
+
|
50
|
+
|
51
|
+
##
|
52
|
+
|
53
|
+
|
54
|
+
def parse_none(text: str, /) -> None:
|
55
|
+
"""Parse text into the None value."""
|
56
|
+
if text == "" or search("None", text, flags=IGNORECASE):
|
57
|
+
return
|
58
|
+
raise ParseNoneError(text=text)
|
59
|
+
|
60
|
+
|
61
|
+
@dataclass(kw_only=True, slots=True)
|
62
|
+
class ParseNoneError(Exception):
|
63
|
+
text: str
|
64
|
+
|
65
|
+
@override
|
66
|
+
def __str__(self) -> str:
|
67
|
+
return f"Unable to parse null value; got {self.text!r}"
|
49
68
|
|
50
69
|
|
51
70
|
##
|
@@ -108,8 +127,10 @@ def strip_and_dedent(text: str, /, *, trailing: bool = False) -> str:
|
|
108
127
|
|
109
128
|
__all__ = [
|
110
129
|
"ParseBoolError",
|
130
|
+
"ParseNoneError",
|
111
131
|
"join_strs",
|
112
132
|
"parse_bool",
|
133
|
+
"parse_none",
|
113
134
|
"repr_encode",
|
114
135
|
"snake_case",
|
115
136
|
"split_str",
|
File without changes
|
File without changes
|