dycw-utilities 0.110.3__py3-none-any.whl → 0.110.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.110.3.dist-info → dycw_utilities-0.110.4.dist-info}/METADATA +1 -1
- {dycw_utilities-0.110.3.dist-info → dycw_utilities-0.110.4.dist-info}/RECORD +9 -9
- utilities/__init__.py +1 -1
- utilities/dataclasses.py +39 -10
- utilities/parse.py +40 -3
- utilities/text.py +4 -1
- utilities/types.py +2 -0
- {dycw_utilities-0.110.3.dist-info → dycw_utilities-0.110.4.dist-info}/WHEEL +0 -0
- {dycw_utilities-0.110.3.dist-info → dycw_utilities-0.110.4.dist-info}/licenses/LICENSE +0 -0
@@ -1,4 +1,4 @@
|
|
1
|
-
utilities/__init__.py,sha256=
|
1
|
+
utilities/__init__.py,sha256=jGUTgOEiXSlv_bOz8eQW5saCU2Pq4oTqEXt6FeWlFII,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=Q197PVnE_vUMn_SNnqJBCo4eRy4bdHtgMHWRbSJPtFk,26670
|
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
|
@@ -41,7 +41,7 @@ utilities/operator.py,sha256=0M2yZJ0PODH47ogFEnkGMBe_cfxwZR02T_92LZVZvHo,3715
|
|
41
41
|
utilities/optuna.py,sha256=loyJGWTzljgdJaoLhP09PT8Jz6o_pwBOwehY33lHkhw,1923
|
42
42
|
utilities/orjson.py,sha256=Wj5pzG_VdgoAy14a7Luhem-BgYrRtRFvvl_POiszRd0,36930
|
43
43
|
utilities/os.py,sha256=D_FyyT-6TtqiN9KSS7c9g1fnUtgxmyMtzAjmYLkk46A,3587
|
44
|
-
utilities/parse.py,sha256=
|
44
|
+
utilities/parse.py,sha256=6erE2TpZP-z0FWtxnnDVO3-X1d1MHoNrr2IYiaJEuk8,18960
|
45
45
|
utilities/pathlib.py,sha256=31WPMXdLIyXgYOMMl_HOI2wlo66MGSE-cgeelk-Lias,1410
|
46
46
|
utilities/period.py,sha256=ikHXsWtDLr553cfH6p9mMaiCnIAP69B7q84ckWV3HaA,10884
|
47
47
|
utilities/pickle.py,sha256=Bhvd7cZl-zQKQDFjUerqGuSKlHvnW1K2QXeU5UZibtg,657
|
@@ -73,11 +73,11 @@ 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=hfcBKF22fKT6s_U-ZdP-g5TjFQ0-NrIrQdvIwERWT80,10971
|
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
|
80
|
-
utilities/types.py,sha256=
|
80
|
+
utilities/types.py,sha256=PZjxTCDYSPFKppi3ZWnSh441mv0rgEvZkh8npqL6awo,18064
|
81
81
|
utilities/typing.py,sha256=gLg4EbE1FX52fJ1d3ji4i08qolwu9qgWt8w_w_Y5DTk,5512
|
82
82
|
utilities/tzdata.py,sha256=2ZsPmhTVM9Ptrxb4QrWKtKOB9RiH8IOO-A1u7ULdVbg,176
|
83
83
|
utilities/tzlocal.py,sha256=42BCquGF54oIqIKe5RGziP4K8Nbm3Ey7uqcNn6m5ge8,534
|
@@ -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.4.dist-info/METADATA,sha256=N7v2g5hRFwzAbpEjcnZs0OZQhPZPECwQHsevYVzsXZg,13004
|
91
|
+
dycw_utilities-0.110.4.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
92
|
+
dycw_utilities-0.110.4.dist-info/licenses/LICENSE,sha256=gppZp16M6nSVpBbUBrNL6JuYfvKwZiKgV7XoKKsHzqo,1066
|
93
|
+
dycw_utilities-0.110.4.dist-info/RECORD,,
|
utilities/__init__.py
CHANGED
utilities/dataclasses.py
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
3
|
from collections.abc import Mapping
|
4
|
+
from contextlib import suppress
|
4
5
|
from dataclasses import MISSING, dataclass, field, fields, replace
|
5
6
|
from typing import (
|
6
7
|
TYPE_CHECKING,
|
@@ -22,16 +23,22 @@ from utilities.functions import (
|
|
22
23
|
from utilities.iterables import OneStrEmptyError, OneStrNonUniqueError, one_str
|
23
24
|
from utilities.operator import is_equal
|
24
25
|
from utilities.parse import ParseObjectError, parse_object, serialize_object
|
26
|
+
from utilities.re import ExtractGroupError, extract_group
|
25
27
|
from utilities.sentinel import Sentinel, sentinel
|
26
28
|
from utilities.text import (
|
29
|
+
BRACKETS,
|
27
30
|
LIST_SEPARATOR,
|
28
31
|
PAIR_SEPARATOR,
|
29
32
|
_SplitKeyValuePairsDuplicateKeysError,
|
30
33
|
_SplitKeyValuePairsSplitError,
|
31
|
-
join_strs,
|
32
34
|
split_key_value_pairs,
|
33
35
|
)
|
34
|
-
from utilities.types import
|
36
|
+
from utilities.types import (
|
37
|
+
ParseObjectExtra,
|
38
|
+
SerializeObjectExtra,
|
39
|
+
StrStrMapping,
|
40
|
+
TDataclass,
|
41
|
+
)
|
35
42
|
from utilities.typing import get_type_hints
|
36
43
|
|
37
44
|
if TYPE_CHECKING:
|
@@ -404,10 +411,11 @@ def serialize_dataclass(
|
|
404
411
|
exclude: Iterable[str] | None = None,
|
405
412
|
rel_tol: float | None = None,
|
406
413
|
abs_tol: float | None = None,
|
407
|
-
|
414
|
+
extra_equal: Mapping[type[_U], Callable[[_U, _U], bool]] | None = None,
|
408
415
|
defaults: bool = False,
|
409
416
|
list_separator: str = LIST_SEPARATOR,
|
410
417
|
pair_separator: str = PAIR_SEPARATOR,
|
418
|
+
extra_serializers: SerializeObjectExtra | None = None,
|
411
419
|
) -> str:
|
412
420
|
"""Serialize a Dataclass."""
|
413
421
|
mapping: StrStrMapping = {}
|
@@ -422,16 +430,21 @@ def serialize_dataclass(
|
|
422
430
|
exclude=exclude,
|
423
431
|
rel_tol=rel_tol,
|
424
432
|
abs_tol=abs_tol,
|
425
|
-
extra=
|
433
|
+
extra=extra_equal,
|
426
434
|
defaults=defaults,
|
427
435
|
):
|
428
436
|
mapping[fld.name] = serialize_object(
|
429
|
-
fld.value,
|
437
|
+
fld.value,
|
438
|
+
list_separator=list_separator,
|
439
|
+
pair_separator=pair_separator,
|
440
|
+
extra=extra_serializers,
|
430
441
|
)
|
431
|
-
|
432
|
-
|
442
|
+
return serialize_object(
|
443
|
+
mapping,
|
444
|
+
list_separator=list_separator,
|
445
|
+
pair_separator=pair_separator,
|
446
|
+
extra=extra_serializers,
|
433
447
|
)
|
434
|
-
return join_strs(joined_items, separator=list_separator)
|
435
448
|
|
436
449
|
|
437
450
|
def parse_dataclass(
|
@@ -441,6 +454,7 @@ def parse_dataclass(
|
|
441
454
|
*,
|
442
455
|
list_separator: str = LIST_SEPARATOR,
|
443
456
|
pair_separator: str = PAIR_SEPARATOR,
|
457
|
+
brackets: Iterable[tuple[str, str]] | None = BRACKETS,
|
444
458
|
globalns: StrMapping | None = None,
|
445
459
|
localns: StrMapping | None = None,
|
446
460
|
warn_name_errors: bool = False,
|
@@ -453,7 +467,11 @@ def parse_dataclass(
|
|
453
467
|
match text_or_mapping:
|
454
468
|
case str() as text:
|
455
469
|
keys_to_serializes = _parse_dataclass_split_key_value_pairs(
|
456
|
-
text,
|
470
|
+
text,
|
471
|
+
cls,
|
472
|
+
list_separator=list_separator,
|
473
|
+
pair_separator=pair_separator,
|
474
|
+
brackets=brackets,
|
457
475
|
)
|
458
476
|
case Mapping() as keys_to_serializes:
|
459
477
|
...
|
@@ -477,7 +495,14 @@ def parse_dataclass(
|
|
477
495
|
)
|
478
496
|
field_names_to_values = {
|
479
497
|
f.name: _parse_dataclass_parse_text(
|
480
|
-
f,
|
498
|
+
f,
|
499
|
+
t,
|
500
|
+
cls,
|
501
|
+
list_separator=list_separator,
|
502
|
+
pair_separator=pair_separator,
|
503
|
+
head=head,
|
504
|
+
case_sensitive=case_sensitive,
|
505
|
+
extra=extra_parsers,
|
481
506
|
)
|
482
507
|
for f, t in fields_to_serializes.items()
|
483
508
|
}
|
@@ -501,12 +526,16 @@ def _parse_dataclass_split_key_value_pairs(
|
|
501
526
|
*,
|
502
527
|
list_separator: str = LIST_SEPARATOR,
|
503
528
|
pair_separator: str = PAIR_SEPARATOR,
|
529
|
+
brackets: Iterable[tuple[str, str]] | None = BRACKETS,
|
504
530
|
) -> StrStrMapping:
|
531
|
+
with suppress(ExtractGroupError):
|
532
|
+
text = extract_group(r"^\{?(.*?)\}?$", text)
|
505
533
|
try:
|
506
534
|
return split_key_value_pairs(
|
507
535
|
text,
|
508
536
|
list_separator=list_separator,
|
509
537
|
pair_separator=pair_separator,
|
538
|
+
brackets=brackets,
|
510
539
|
mapping=True,
|
511
540
|
)
|
512
541
|
except _SplitKeyValuePairsSplitError as error:
|
utilities/parse.py
CHANGED
@@ -31,7 +31,7 @@ from utilities.text import (
|
|
31
31
|
split_key_value_pairs,
|
32
32
|
split_str,
|
33
33
|
)
|
34
|
-
from utilities.types import Duration, Number, ParseObjectExtra
|
34
|
+
from utilities.types import Duration, Number, ParseObjectExtra, SerializeObjectExtra
|
35
35
|
from utilities.typing import (
|
36
36
|
get_args,
|
37
37
|
is_dict_type,
|
@@ -240,7 +240,7 @@ def _parse_object_type(
|
|
240
240
|
) from None
|
241
241
|
else:
|
242
242
|
return parser(text)
|
243
|
-
raise _ParseObjectParseError(type_=cls, text=text)
|
243
|
+
raise _ParseObjectParseError(type_=cls, text=text)
|
244
244
|
|
245
245
|
|
246
246
|
def _parse_object_dict_type(
|
@@ -466,6 +466,7 @@ def serialize_object(
|
|
466
466
|
*,
|
467
467
|
list_separator: str = LIST_SEPARATOR,
|
468
468
|
pair_separator: str = PAIR_SEPARATOR,
|
469
|
+
extra: SerializeObjectExtra | None = None,
|
469
470
|
) -> str:
|
470
471
|
"""Convert an object to text."""
|
471
472
|
if (obj is None) or isinstance(
|
@@ -506,7 +507,9 @@ def serialize_object(
|
|
506
507
|
return _serialize_object_set(
|
507
508
|
obj, list_separator=list_separator, pair_separator=pair_separator
|
508
509
|
)
|
509
|
-
|
510
|
+
if extra is not None:
|
511
|
+
return _serialize_object_extra(obj, extra)
|
512
|
+
raise _SerializeObjectSerializeError(obj=obj)
|
510
513
|
|
511
514
|
|
512
515
|
def _serialize_object_dict(
|
@@ -534,6 +537,19 @@ def _serialize_object_dict(
|
|
534
537
|
return f"{{{joined}}}"
|
535
538
|
|
536
539
|
|
540
|
+
def _serialize_object_extra(obj: Any, extra: SerializeObjectExtra, /) -> str:
|
541
|
+
try:
|
542
|
+
serializer = one(s for c, s in extra.items() if isinstance(obj, c))
|
543
|
+
except OneEmptyError:
|
544
|
+
raise _SerializeObjectSerializeError(obj=obj) from None
|
545
|
+
except OneNonUniqueError as error:
|
546
|
+
raise _SerializeObjectExtraNonUniqueError(
|
547
|
+
obj=obj, first=error.first, second=error.second
|
548
|
+
) from None
|
549
|
+
else:
|
550
|
+
return serializer(obj)
|
551
|
+
|
552
|
+
|
537
553
|
def _serialize_object_list(
|
538
554
|
obj: Sequence[Any],
|
539
555
|
/,
|
@@ -585,4 +601,25 @@ def _serialize_object_tuple(
|
|
585
601
|
return f"({joined})"
|
586
602
|
|
587
603
|
|
604
|
+
@dataclass(kw_only=True, slots=True)
|
605
|
+
class SerializeObjectError(Exception):
|
606
|
+
obj: Any
|
607
|
+
|
608
|
+
|
609
|
+
class _SerializeObjectSerializeError(SerializeObjectError):
|
610
|
+
@override
|
611
|
+
def __str__(self) -> str:
|
612
|
+
return f"Unable to serialize object {self.obj!r}"
|
613
|
+
|
614
|
+
|
615
|
+
@dataclass
|
616
|
+
class _SerializeObjectExtraNonUniqueError(SerializeObjectError):
|
617
|
+
first: type[Any]
|
618
|
+
second: type[Any]
|
619
|
+
|
620
|
+
@override
|
621
|
+
def __str__(self) -> str:
|
622
|
+
return f"Unable to serialize object {self.obj!r} since `extra` must contain exactly one parent class; got {self.first!r}, {self.second!r} and perhaps more"
|
623
|
+
|
624
|
+
|
588
625
|
__all__ = ["parse_object", "serialize_object"]
|
utilities/text.py
CHANGED
@@ -144,7 +144,10 @@ def split_key_value_pairs(
|
|
144
144
|
except SplitStrError as error:
|
145
145
|
raise _SplitKeyValuePairsSplitError(text=text, inner=error.text) from None
|
146
146
|
try:
|
147
|
-
pairs = [
|
147
|
+
pairs = [
|
148
|
+
split_str(text_i, separator=pair_separator, brackets=brackets, n=2)
|
149
|
+
for text_i in texts
|
150
|
+
]
|
148
151
|
except SplitStrError as error:
|
149
152
|
raise _SplitKeyValuePairsSplitError(text=text, inner=error.text) from None
|
150
153
|
if not mapping:
|
utilities/types.py
CHANGED
@@ -232,6 +232,7 @@ class SupportsRound(Protocol[_T_co]):
|
|
232
232
|
|
233
233
|
# parse
|
234
234
|
type ParseObjectExtra = Mapping[Any, Callable[[str], Any]]
|
235
|
+
type SerializeObjectExtra = Mapping[type[Any], Callable[[Any], str]]
|
235
236
|
|
236
237
|
|
237
238
|
# pathlib
|
@@ -288,6 +289,7 @@ __all__ = [
|
|
288
289
|
"PathLikeOrCallable",
|
289
290
|
"RoundMode",
|
290
291
|
"Seed",
|
292
|
+
"SerializeObjectExtra",
|
291
293
|
"StrMapping",
|
292
294
|
"StrStrMapping",
|
293
295
|
"SupportsAbs",
|
File without changes
|
File without changes
|