dycw-utilities 0.110.0__py3-none-any.whl → 0.110.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.110.0.dist-info → dycw_utilities-0.110.2.dist-info}/METADATA +1 -1
- {dycw_utilities-0.110.0.dist-info → dycw_utilities-0.110.2.dist-info}/RECORD +7 -7
- utilities/__init__.py +1 -1
- utilities/dataclasses.py +2 -2
- utilities/text.py +132 -11
- {dycw_utilities-0.110.0.dist-info → dycw_utilities-0.110.2.dist-info}/WHEEL +0 -0
- {dycw_utilities-0.110.0.dist-info → dycw_utilities-0.110.2.dist-info}/licenses/LICENSE +0 -0
@@ -1,4 +1,4 @@
|
|
1
|
-
utilities/__init__.py,sha256=
|
1
|
+
utilities/__init__.py,sha256=N5L_-mBy__dabTcP63GXeZ0UmhNEqKjJ0SR5XKVgg5Y,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=41oQUurWMvadFK5gFnaG21hMM0Vmfn2WS6OpC0R9mas,14757
|
@@ -11,7 +11,7 @@ utilities/contextlib.py,sha256=OOIIEa5lXKGzFAnauaul40nlQnQko6Na4ryiMJcHkIg,478
|
|
11
11
|
utilities/contextvars.py,sha256=RsSGGrbQqqZ67rOydnM7WWIsM2lIE31UHJLejnHJPWY,505
|
12
12
|
utilities/cryptography.py,sha256=HyOewI20cl3uRXsKivhIaeLVDInQdzgXZGaly7hS5dE,771
|
13
13
|
utilities/cvxpy.py,sha256=Rv1-fD-XYerosCavRF8Pohop2DBkU3AlFaGTfD8AEAA,13776
|
14
|
-
utilities/dataclasses.py,sha256=
|
14
|
+
utilities/dataclasses.py,sha256=e2YuCj1DF4eecFFxsu20MknghXJ4SNkWCmbIAOXXr18,25942
|
15
15
|
utilities/datetime.py,sha256=GOs-MIEW_A49kzqa1yhIoeNeSqqPVgGO-h2AThtgTDk,37326
|
16
16
|
utilities/enum.py,sha256=HoRwVCWzsnH0vpO9ZEcAAIZLMv0Sn2vJxxA4sYMQgDs,5793
|
17
17
|
utilities/errors.py,sha256=BtSNP0JC3ik536ddPyTerLomCRJV9f6kdMe6POz0QHM,361
|
@@ -73,7 +73,7 @@ utilities/streamlit.py,sha256=U9PJBaKP1IdSykKhPZhIzSPTZsmLsnwbEPZWzNhJPKk,2955
|
|
73
73
|
utilities/sys.py,sha256=h0Xr7Vj86wNalvwJVP1wj5Y0kD_VWm1vzuXZ_jw94mE,2743
|
74
74
|
utilities/tempfile.py,sha256=VqmZJAhTJ1OaVywFzk5eqROV8iJbW9XQ_QYAV0bpdRo,1384
|
75
75
|
utilities/tenacity.py,sha256=1PUvODiBVgeqIh7G5TRt5WWMSqjLYkEqP53itT97WQc,4914
|
76
|
-
utilities/text.py,sha256=
|
76
|
+
utilities/text.py,sha256=VcNAJtjA2BOGEVY6yXnC9UIAsgECgiWCQ_QnpilZV2o,10089
|
77
77
|
utilities/threading.py,sha256=GvBOp4CyhHfN90wGXZuA2VKe9fGzMaEa7oCl4f3nnPU,1009
|
78
78
|
utilities/timer.py,sha256=Rkc49KSpHuC8s7vUxGO9DU55U9I6yDKnchsQqrUCVBs,4075
|
79
79
|
utilities/traceback.py,sha256=KwHPLdEbdj0fFhXo8MBfxcvem8A-VXYDwFMNJ6f0cTM,27328
|
@@ -87,7 +87,7 @@ utilities/warnings.py,sha256=yUgjnmkCRf6QhdyAXzl7u0qQFejhQG3PrjoSwxpbHrs,1819
|
|
87
87
|
utilities/whenever.py,sha256=TjoTAJ1R27-rKXiXzdE4GzPidmYqm0W58XydDXp-QZM,17786
|
88
88
|
utilities/zipfile.py,sha256=24lQc9ATcJxHXBPc_tBDiJk48pWyRrlxO2fIsFxU0A8,699
|
89
89
|
utilities/zoneinfo.py,sha256=-DQz5a0Ikw9jfSZtL0BEQkXOMC9yGn_xiJYNCLMiqEc,1989
|
90
|
-
dycw_utilities-0.110.
|
91
|
-
dycw_utilities-0.110.
|
92
|
-
dycw_utilities-0.110.
|
93
|
-
dycw_utilities-0.110.
|
90
|
+
dycw_utilities-0.110.2.dist-info/METADATA,sha256=TK9SINDsRCnIKjF2YyzOvlQ5mTpD1hjJJ6SD_aNKFI4,13004
|
91
|
+
dycw_utilities-0.110.2.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
92
|
+
dycw_utilities-0.110.2.dist-info/licenses/LICENSE,sha256=gppZp16M6nSVpBbUBrNL6JuYfvKwZiKgV7XoKKsHzqo,1066
|
93
|
+
dycw_utilities-0.110.2.dist-info/RECORD,,
|
utilities/__init__.py
CHANGED
utilities/dataclasses.py
CHANGED
@@ -439,7 +439,7 @@ def serialize_dataclass(
|
|
439
439
|
|
440
440
|
|
441
441
|
def parse_dataclass(
|
442
|
-
text_or_mapping: str |
|
442
|
+
text_or_mapping: str | StrStrMapping,
|
443
443
|
cls: type[TDataclass],
|
444
444
|
/,
|
445
445
|
*,
|
@@ -505,7 +505,7 @@ def _parse_dataclass_split_key_value_pairs(
|
|
505
505
|
*,
|
506
506
|
list_separator: str = LIST_SEPARATOR,
|
507
507
|
pair_separator: str = PAIR_SEPARATOR,
|
508
|
-
) ->
|
508
|
+
) -> StrStrMapping:
|
509
509
|
try:
|
510
510
|
return split_key_value_pairs(
|
511
511
|
text,
|
utilities/text.py
CHANGED
@@ -1,12 +1,14 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
3
|
import re
|
4
|
+
from collections import deque
|
4
5
|
from dataclasses import dataclass
|
5
|
-
from
|
6
|
+
from itertools import chain
|
7
|
+
from re import IGNORECASE, Match, escape, search
|
6
8
|
from textwrap import dedent
|
7
9
|
from typing import TYPE_CHECKING, Any, Literal, overload, override
|
8
10
|
|
9
|
-
from utilities.iterables import CheckDuplicatesError, check_duplicates
|
11
|
+
from utilities.iterables import CheckDuplicatesError, check_duplicates, transpose
|
10
12
|
from utilities.reprlib import get_repr
|
11
13
|
|
12
14
|
if TYPE_CHECKING:
|
@@ -167,47 +169,134 @@ class _SplitKeyValuePairsDuplicateKeysError(SplitKeyValuePairsError):
|
|
167
169
|
|
168
170
|
|
169
171
|
@overload
|
170
|
-
def split_str(
|
172
|
+
def split_str(
|
173
|
+
text: str,
|
174
|
+
/,
|
175
|
+
*,
|
176
|
+
separator: str = ",",
|
177
|
+
brackets: Iterable[tuple[str, str]] | None = None,
|
178
|
+
n: Literal[1],
|
179
|
+
) -> tuple[str]: ...
|
171
180
|
@overload
|
172
181
|
def split_str(
|
173
|
-
text: str,
|
182
|
+
text: str,
|
183
|
+
/,
|
184
|
+
*,
|
185
|
+
separator: str = ",",
|
186
|
+
brackets: Iterable[tuple[str, str]] | None = None,
|
187
|
+
n: Literal[2],
|
174
188
|
) -> tuple[str, str]: ...
|
175
189
|
@overload
|
176
190
|
def split_str(
|
177
|
-
text: str,
|
191
|
+
text: str,
|
192
|
+
/,
|
193
|
+
*,
|
194
|
+
separator: str = ",",
|
195
|
+
brackets: Iterable[tuple[str, str]] | None = None,
|
196
|
+
n: Literal[3],
|
178
197
|
) -> tuple[str, str, str]: ...
|
179
198
|
@overload
|
180
199
|
def split_str(
|
181
|
-
text: str,
|
200
|
+
text: str,
|
201
|
+
/,
|
202
|
+
*,
|
203
|
+
separator: str = ",",
|
204
|
+
brackets: Iterable[tuple[str, str]] | None = None,
|
205
|
+
n: Literal[4],
|
182
206
|
) -> tuple[str, str, str, str]: ...
|
183
207
|
@overload
|
184
208
|
def split_str(
|
185
|
-
text: str,
|
209
|
+
text: str,
|
210
|
+
/,
|
211
|
+
*,
|
212
|
+
separator: str = ",",
|
213
|
+
brackets: Iterable[tuple[str, str]] | None = None,
|
214
|
+
n: Literal[5],
|
186
215
|
) -> tuple[str, str, str, str, str]: ...
|
187
216
|
@overload
|
188
217
|
def split_str(
|
189
|
-
text: str,
|
218
|
+
text: str,
|
219
|
+
/,
|
220
|
+
*,
|
221
|
+
separator: str = ",",
|
222
|
+
brackets: Iterable[tuple[str, str]] | None = None,
|
223
|
+
n: int | None = None,
|
190
224
|
) -> Sequence[str]: ...
|
191
225
|
def split_str(
|
192
|
-
text: str,
|
226
|
+
text: str,
|
227
|
+
/,
|
228
|
+
*,
|
229
|
+
separator: str = ",",
|
230
|
+
brackets: Iterable[tuple[str, str]] | None = None,
|
231
|
+
n: int | None = None,
|
193
232
|
) -> Sequence[str]:
|
194
233
|
"""Split a string, with a special provision for the empty string."""
|
195
234
|
if text == "":
|
196
235
|
texts = []
|
197
236
|
elif text == _escape_separator(separator=separator):
|
198
237
|
texts = [""]
|
199
|
-
|
238
|
+
elif brackets is None:
|
200
239
|
texts = text.split(separator)
|
240
|
+
else:
|
241
|
+
texts = _split_str_brackets(text, brackets, separator=separator)
|
201
242
|
if n is None:
|
202
243
|
return texts
|
203
244
|
if len(texts) != n:
|
204
|
-
raise
|
245
|
+
raise _SplitStrCountError(text=text, n=n, texts=texts)
|
205
246
|
return tuple(texts)
|
206
247
|
|
207
248
|
|
249
|
+
def _split_str_brackets(
|
250
|
+
text: str, brackets: Iterable[tuple[str, str]], /, *, separator: str = ","
|
251
|
+
) -> Sequence[str]:
|
252
|
+
brackets = list(brackets)
|
253
|
+
opens, closes = transpose(brackets)
|
254
|
+
close_to_open = {close: open_ for open_, close in brackets}
|
255
|
+
|
256
|
+
escapes = map(escape, chain(chain.from_iterable(brackets), [separator]))
|
257
|
+
pattern = re.compile("|".join(escapes))
|
258
|
+
|
259
|
+
results: Sequence[str] = []
|
260
|
+
stack: deque[tuple[str, int]] = deque()
|
261
|
+
last = 0
|
262
|
+
|
263
|
+
for match in pattern.finditer(text):
|
264
|
+
token, position = match.group(), match.start()
|
265
|
+
if token in opens:
|
266
|
+
stack.append((token, position))
|
267
|
+
elif token in closes:
|
268
|
+
if len(stack) == 0:
|
269
|
+
raise _SplitStrClosingBracketUnmatchedError(
|
270
|
+
text=text, token=token, position=position
|
271
|
+
)
|
272
|
+
open_token, open_position = stack.pop()
|
273
|
+
if open_token != close_to_open[token]:
|
274
|
+
raise _SplitStrClosingBracketMismatchedError(
|
275
|
+
text=text,
|
276
|
+
opening_token=open_token,
|
277
|
+
opening_position=open_position,
|
278
|
+
closing_token=token,
|
279
|
+
closing_position=position,
|
280
|
+
)
|
281
|
+
elif (token == separator) and (len(stack) == 0):
|
282
|
+
results.append(text[last:position].strip())
|
283
|
+
last = position + 1
|
284
|
+
results.append(text[last:].strip())
|
285
|
+
if len(stack) >= 1:
|
286
|
+
token, position = stack.pop()
|
287
|
+
raise _SplitStrOpeningBracketUnmatchedError(
|
288
|
+
text=text, token=token, position=position
|
289
|
+
)
|
290
|
+
return results
|
291
|
+
|
292
|
+
|
208
293
|
@dataclass(kw_only=True, slots=True)
|
209
294
|
class SplitStrError(Exception):
|
210
295
|
text: str
|
296
|
+
|
297
|
+
|
298
|
+
@dataclass(kw_only=True, slots=True)
|
299
|
+
class _SplitStrCountError(SplitStrError):
|
211
300
|
n: int
|
212
301
|
texts: Sequence[str]
|
213
302
|
|
@@ -216,6 +305,38 @@ class SplitStrError(Exception):
|
|
216
305
|
return f"Unable to split {self.text!r} into {self.n} part(s); got {len(self.texts)}"
|
217
306
|
|
218
307
|
|
308
|
+
@dataclass(kw_only=True, slots=True)
|
309
|
+
class _SplitStrClosingBracketMismatchedError(SplitStrError):
|
310
|
+
opening_token: str
|
311
|
+
opening_position: int
|
312
|
+
closing_token: str
|
313
|
+
closing_position: int
|
314
|
+
|
315
|
+
@override
|
316
|
+
def __str__(self) -> str:
|
317
|
+
return f"Unable to split {self.text!r}; got mismatched {self.opening_token!r} at position {self.opening_position} and {self.closing_token!r} at position {self.closing_position}"
|
318
|
+
|
319
|
+
|
320
|
+
@dataclass(kw_only=True, slots=True)
|
321
|
+
class _SplitStrClosingBracketUnmatchedError(SplitStrError):
|
322
|
+
token: str
|
323
|
+
position: int
|
324
|
+
|
325
|
+
@override
|
326
|
+
def __str__(self) -> str:
|
327
|
+
return f"Unable to split {self.text!r}; got unmatched {self.token!r} at position {self.position}"
|
328
|
+
|
329
|
+
|
330
|
+
@dataclass(kw_only=True, slots=True)
|
331
|
+
class _SplitStrOpeningBracketUnmatchedError(SplitStrError):
|
332
|
+
token: str
|
333
|
+
position: int
|
334
|
+
|
335
|
+
@override
|
336
|
+
def __str__(self) -> str:
|
337
|
+
return f"Unable to split {self.text!r}; got unmatched {self.token!r} at position {self.position}"
|
338
|
+
|
339
|
+
|
219
340
|
def join_strs(
|
220
341
|
texts: Iterable[str], /, *, sort: bool = False, separator: str = ","
|
221
342
|
) -> str:
|
File without changes
|
File without changes
|