dycw-utilities 0.110.6__py3-none-any.whl → 0.110.7__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: dycw-utilities
3
- Version: 0.110.6
3
+ Version: 0.110.7
4
4
  Author-email: Derek Wan <d.wan@icloud.com>
5
5
  License-File: LICENSE
6
6
  Requires-Python: >=3.12
@@ -1,4 +1,4 @@
1
- utilities/__init__.py,sha256=ob4l7mBwFaS3Yaje03_AcerZOVTXkba6PSattZmooZA,60
1
+ utilities/__init__.py,sha256=RH75kOPQZPuI3PzW-iy4R8ZfTSbKQHPjZwc14TPFLN8,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
@@ -18,7 +18,7 @@ utilities/errors.py,sha256=BtSNP0JC3ik536ddPyTerLomCRJV9f6kdMe6POz0QHM,361
18
18
  utilities/eventkit.py,sha256=6M5Xu1SzN-juk9PqBHwy5dS-ta7T0qA6SMpDsakOJ0E,13039
19
19
  utilities/fastapi.py,sha256=uwqOGbGwzIbP-lfm-ApG1ZEN3BA_TDsaiuTghhLmxb8,2413
20
20
  utilities/fpdf2.py,sha256=zM3gwOYcAfv7P4qhbyvzPmRY4PPAiAQ-ZnPC6I9SZ1M,1832
21
- utilities/functions.py,sha256=yAoJoopaxf9ip6mJC5Ui7b0GyYhE-gvl0kDkoI8agZw,27667
21
+ utilities/functions.py,sha256=lAJeERNrmcpwon3drcTIlizLVRd8D-gdXojxtKFN0LM,28736
22
22
  utilities/functools.py,sha256=WrpHt7NLNWSUn9A1Q_ZIWlNaYZOEI4IFKyBG9HO3BC4,1643
23
23
  utilities/getpass.py,sha256=DfN5UgMAtFCqS3dSfFHUfqIMZX2shXvwphOz_6J6f6A,103
24
24
  utilities/git.py,sha256=wpt5dZ5Oi5931pN24_VLZYaQOvmR0OcQuVtgHzFUN1k,2359
@@ -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=zfvVczg4wQUvjgCEa_y36LSeY9WFbsdibI3n4S7_gzA,19076
44
+ utilities/parse.py,sha256=fki2mnPGa1Ex-aeWiXDkUBHWb7FEk4F6AzMiHjqHXdw,19081
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
@@ -87,7 +87,7 @@ utilities/warnings.py,sha256=un1LvHv70PU-LLv8RxPVmugTzDJkkGXRMZTE2-fTQHw,1771
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.6.dist-info/METADATA,sha256=yWIsOFSUfhENwHLyGfluM7z4Mu196QFRVefbcAqROf4,13004
91
- dycw_utilities-0.110.6.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
92
- dycw_utilities-0.110.6.dist-info/licenses/LICENSE,sha256=gppZp16M6nSVpBbUBrNL6JuYfvKwZiKgV7XoKKsHzqo,1066
93
- dycw_utilities-0.110.6.dist-info/RECORD,,
90
+ dycw_utilities-0.110.7.dist-info/METADATA,sha256=wFw9aZuOwiyPR1o4QtTmz5fPx9y5gBbKheuvV0XKhA8,13004
91
+ dycw_utilities-0.110.7.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
92
+ dycw_utilities-0.110.7.dist-info/licenses/LICENSE,sha256=gppZp16M6nSVpBbUBrNL6JuYfvKwZiKgV7XoKKsHzqo,1066
93
+ dycw_utilities-0.110.7.dist-info/RECORD,,
utilities/__init__.py CHANGED
@@ -1,3 +1,3 @@
1
1
  from __future__ import annotations
2
2
 
3
- __version__ = "0.110.6"
3
+ __version__ = "0.110.7"
utilities/functions.py CHANGED
@@ -22,6 +22,7 @@ from typing import (
22
22
  Literal,
23
23
  TypeGuard,
24
24
  TypeVar,
25
+ assert_never,
25
26
  cast,
26
27
  overload,
27
28
  override,
@@ -182,6 +183,8 @@ def ensure_class(
182
183
  *,
183
184
  nullable: Literal[False] = False,
184
185
  ) -> _T1 | _T2 | _T3 | _T4 | _T5: ...
186
+ @overload
187
+ def ensure_class(obj: Any, cls: TypeLike[_T], /, *, nullable: bool = False) -> Any: ...
185
188
  def ensure_class(obj: Any, cls: TypeLike[_T], /, *, nullable: bool = False) -> Any:
186
189
  """Ensure an object is of the required class."""
187
190
  if isinstance(obj, cls) or ((obj is None) and nullable):
@@ -657,9 +660,23 @@ def is_hashable(obj: Any, /) -> TypeGuard[Hashable]:
657
660
  ##
658
661
 
659
662
 
660
- def is_instance_int_not_bool(obj: Any, /) -> TypeGuard[int]:
661
- """Check if an object is an integer, and not a boolean."""
662
- return isinstance(obj, int) and not isinstance(obj, bool)
663
+ def is_instance_not_bool_int(
664
+ obj: Any, class_or_tuple: TypeLike[Any], /
665
+ ) -> TypeGuard[int]:
666
+ """Check if an instance relationship holds, except bool<int."""
667
+ match class_or_tuple:
668
+ case type() as type_:
669
+ return _is_instance_not_bool_int(obj, type_)
670
+ case tuple() as types:
671
+ return any(_is_instance_not_bool_int(obj, p) for p in types)
672
+ case _ as never:
673
+ assert_never(never)
674
+
675
+
676
+ def _is_instance_not_bool_int(obj: Any, type_: type[Any], /) -> bool:
677
+ return isinstance(obj, type_) and not (
678
+ isinstance(obj, bool) and issubclass(type_, int) and not issubclass(type_, bool)
679
+ )
663
680
 
664
681
 
665
682
  ##
@@ -779,9 +796,23 @@ def is_string_mapping(obj: Any, /) -> TypeGuard[StrMapping]:
779
796
  ##
780
797
 
781
798
 
782
- def is_subclass_int_not_bool(cls: type[Any], /) -> TypeGuard[type[int]]:
783
- """Check if a class is an integer, and not a boolean."""
784
- return issubclass(cls, int) and not issubclass(cls, bool)
799
+ def is_subclass_not_bool_int(cls: type[Any], class_or_tuple: TypeLike[Any], /) -> bool:
800
+ """Check if a subclass relationship holds, except bool<int."""
801
+ match class_or_tuple:
802
+ case type() as parent:
803
+ return _is_subclass_int_not_bool_one(cls, parent)
804
+ case tuple() as parents:
805
+ return any(_is_subclass_int_not_bool_one(cls, p) for p in parents)
806
+ case _ as never:
807
+ assert_never(never)
808
+
809
+
810
+ def _is_subclass_int_not_bool_one(cls: type[Any], parent: type[Any], /) -> bool:
811
+ return issubclass(cls, parent) and not (
812
+ issubclass(cls, bool)
813
+ and issubclass(parent, int)
814
+ and not issubclass(parent, bool)
815
+ )
785
816
 
786
817
 
787
818
  ##
@@ -1044,7 +1075,7 @@ __all__ = [
1044
1075
  "is_dataclass_class",
1045
1076
  "is_dataclass_instance",
1046
1077
  "is_hashable",
1047
- "is_instance_int_not_bool",
1078
+ "is_instance_not_bool_int",
1048
1079
  "is_iterable_of",
1049
1080
  "is_none",
1050
1081
  "is_not_none",
@@ -1052,7 +1083,7 @@ __all__ = [
1052
1083
  "is_sized",
1053
1084
  "is_sized_not_str",
1054
1085
  "is_string_mapping",
1055
- "is_subclass_int_not_bool",
1086
+ "is_subclass_not_bool_int",
1056
1087
  "is_tuple",
1057
1088
  "is_tuple_or_str_mapping",
1058
1089
  "make_isinstance",
utilities/parse.py CHANGED
@@ -14,7 +14,7 @@ from utilities.datetime import (
14
14
  is_subclass_date_not_datetime,
15
15
  )
16
16
  from utilities.enum import ParseEnumError, parse_enum
17
- from utilities.functions import is_subclass_int_not_bool
17
+ from utilities.functions import is_subclass_not_bool_int
18
18
  from utilities.iterables import OneEmptyError, OneNonUniqueError, one, one_str
19
19
  from utilities.math import ParseNumberError, parse_number
20
20
  from utilities.re import ExtractGroupError, extract_group
@@ -174,7 +174,7 @@ def _parse_object_type(
174
174
  return parse_bool(text)
175
175
  except ParseBoolError:
176
176
  raise _ParseObjectParseError(type_=cls, text=text) from None
177
- if is_subclass_int_not_bool(cls):
177
+ if is_subclass_not_bool_int(cls, int):
178
178
  try:
179
179
  return int(text)
180
180
  except ValueError: