dycw-utilities 0.148.0__py3-none-any.whl → 0.148.1__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.148.0
3
+ Version: 0.148.1
4
4
  Author-email: Derek Wan <d.wan@icloud.com>
5
5
  License-File: LICENSE
6
6
  Requires-Python: >=3.12
@@ -14,7 +14,7 @@ Provides-Extra: test
14
14
  Requires-Dist: dycw-pytest-only<2.2,>=2.1.1; extra == 'test'
15
15
  Requires-Dist: hypothesis<6.136,>=6.135.24; extra == 'test'
16
16
  Requires-Dist: pudb<2025.2,>=2025.1; extra == 'test'
17
- Requires-Dist: pytest-asyncio<1.1,>=1.0.0; extra == 'test'
17
+ Requires-Dist: pytest-asyncio<1.2,>=1.1.0; extra == 'test'
18
18
  Requires-Dist: pytest-cov<6.3,>=6.2.1; extra == 'test'
19
19
  Requires-Dist: pytest-instafail<0.6,>=0.5.0; extra == 'test'
20
20
  Requires-Dist: pytest-lazy-fixtures<1.2,>=1.1.4; extra == 'test'
@@ -1,6 +1,6 @@
1
- utilities/__init__.py,sha256=2TRLfWl0dK_2ThOu9hSeTmoG0iZ_XFR_8beebjQMWqg,60
1
+ utilities/__init__.py,sha256=iMEViWolW9oRg6PDmC46RTFOqP-O9BCaLj3gJai78wg,60
2
2
  utilities/altair.py,sha256=92E2lCdyHY4Zb-vCw6rEJIsWdKipuu-Tu2ab1ufUfAk,9079
3
- utilities/asyncio.py,sha256=J40KmMxTfpgj-GaTNikN0uQNpJnKqqViTD9IRYUvlvM,15985
3
+ utilities/asyncio.py,sha256=z0w3fb-U5Ml5YXVaFFPClizXaQmjDO6YgZg-V9QL0VQ,16021
4
4
  utilities/atomicwrites.py,sha256=xcOWenTBRS0oat3kg7Sqe51AohNThMQ2ixPL7QCG8hw,5795
5
5
  utilities/atools.py,sha256=9im2g8OCf-Iynqa8bAv8N0Ycj9QvrJmGO7yLCZEdgII,986
6
6
  utilities/cachetools.py,sha256=v1-9sXHLdOLiwmkq6NB0OUbxeKBuVVN6wmAWefWoaHI,2744
@@ -12,7 +12,7 @@ utilities/cryptography.py,sha256=_CiK_K6c_-uQuUhsUNjNjTL-nqxAh4_1zTfS11Xe120,972
12
12
  utilities/cvxpy.py,sha256=Rv1-fD-XYerosCavRF8Pohop2DBkU3AlFaGTfD8AEAA,13776
13
13
  utilities/dataclasses.py,sha256=1-REGxtzCo2BbGkjLw5idjbTaiItpOiWvMNbVkJrFXM,32663
14
14
  utilities/enum.py,sha256=IEPMGiNJBcofGPuoGZErf4bMNSBE4SLs32nvm2r81h0,5791
15
- utilities/errors.py,sha256=nC7ZYtxxDBMfrTHtT_MByBfup_wfGQFRo3eDt-0ZPe8,1045
15
+ utilities/errors.py,sha256=k_VvqSi6geTYhlzRRQaGN2j6ZGng-AD8SnX7Znrirm4,1484
16
16
  utilities/eventkit.py,sha256=s9p3WjGc7h7TdbSgVfHrRNNiuOXcQoVQ5sFCbJyqg48,12646
17
17
  utilities/fastapi.py,sha256=3wpd63Tw9paSyy7STpAD7GGe8fLkLaRC6TPCwIGm1BU,1361
18
18
  utilities/fpdf2.py,sha256=776PkEX5xEK-whFOzqaVaQVHPy1Xf01kCSyj7TEp80g,1886
@@ -75,7 +75,7 @@ utilities/threading.py,sha256=GvBOp4CyhHfN90wGXZuA2VKe9fGzMaEa7oCl4f3nnPU,1009
75
75
  utilities/timer.py,sha256=oXfTii6ymu57niP0BDGZjFD55LEHi2a19kqZKiTgaFQ,2588
76
76
  utilities/traceback.py,sha256=-e1D3cMHJCMbggZVFeKVzyAzHCteEcoPc3-3eY0Dtj8,9187
77
77
  utilities/typed_settings.py,sha256=-mzQP5ZCIGWOhm7nPxlajWQhgtX657HVnRCfUYGKQKs,4433
78
- utilities/types.py,sha256=AssdaYdASdtE0HUsdYcagR9lXdt6Bv0QOqP_USm50CQ,18010
78
+ utilities/types.py,sha256=iDfk_Z96v7cIxPlgGYMap0fYmjgRUJ7uQzPPCQe1odY,18115
79
79
  utilities/typing.py,sha256=Z-_XDaWyT_6wIo3qfNK-hvRlzxP2Jxa9PgXzm5rDYRA,13790
80
80
  utilities/tzdata.py,sha256=fgNVj66yUbCSI_-vrRVzSD3gtf-L_8IEJEPjP_Jel5Y,266
81
81
  utilities/tzlocal.py,sha256=KyCXEgCTjqGFx-389JdTuhMRUaT06U1RCMdWoED-qro,728
@@ -88,8 +88,8 @@ utilities/zoneinfo.py,sha256=oEH-nL3t4h9uawyZqWDtNtDAl6M-CLpLYGI_nI6DulM,1971
88
88
  utilities/pytest_plugins/__init__.py,sha256=U4S_2y3zgLZVfMenHRaJFBW8yqh2mUBuI291LGQVOJ8,35
89
89
  utilities/pytest_plugins/pytest_randomly.py,sha256=NXzCcGKbpgYouz5yehKb4jmxmi2SexKKpgF4M65bi10,414
90
90
  utilities/pytest_plugins/pytest_regressions.py,sha256=Iwhfv_OJH7UCPZCfoh7ugZ2Xjqjil-BBBsOb8sDwiGI,1471
91
- dycw_utilities-0.148.0.dist-info/METADATA,sha256=xk8TDabhrZWpV7yjJMe8lvY3v4ut2CWbfjcRHyIdRVg,1697
92
- dycw_utilities-0.148.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
93
- dycw_utilities-0.148.0.dist-info/entry_points.txt,sha256=BOD_SoDxwsfJYOLxhrSXhHP_T7iw-HXI9f2WVkzYxvQ,135
94
- dycw_utilities-0.148.0.dist-info/licenses/LICENSE,sha256=gppZp16M6nSVpBbUBrNL6JuYfvKwZiKgV7XoKKsHzqo,1066
95
- dycw_utilities-0.148.0.dist-info/RECORD,,
91
+ dycw_utilities-0.148.1.dist-info/METADATA,sha256=loLMrx_55h6ZZhUdA2rWHGRDwCsc94yJto0LWyv8DE8,1697
92
+ dycw_utilities-0.148.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
93
+ dycw_utilities-0.148.1.dist-info/entry_points.txt,sha256=BOD_SoDxwsfJYOLxhrSXhHP_T7iw-HXI9f2WVkzYxvQ,135
94
+ dycw_utilities-0.148.1.dist-info/licenses/LICENSE,sha256=gppZp16M6nSVpBbUBrNL6JuYfvKwZiKgV7XoKKsHzqo,1066
95
+ dycw_utilities-0.148.1.dist-info/RECORD,,
utilities/__init__.py CHANGED
@@ -1,3 +1,3 @@
1
1
  from __future__ import annotations
2
2
 
3
- __version__ = "0.148.0"
3
+ __version__ = "0.148.1"
utilities/asyncio.py CHANGED
@@ -35,7 +35,7 @@ from typing import (
35
35
  override,
36
36
  )
37
37
 
38
- from utilities.errors import ImpossibleCaseError
38
+ from utilities.errors import ImpossibleCaseError, is_instance_error
39
39
  from utilities.functions import ensure_int, ensure_not_none, to_bool
40
40
  from utilities.logging import get_logger
41
41
  from utilities.random import SYSTEM_RANDOM
@@ -65,6 +65,7 @@ if TYPE_CHECKING:
65
65
  from utilities.types import (
66
66
  Coro,
67
67
  Delta,
68
+ ExceptionTypeLike,
68
69
  LoggerOrName,
69
70
  MaybeCallableBool,
70
71
  MaybeType,
@@ -398,7 +399,7 @@ async def loop_until_succeed(
398
399
  /,
399
400
  *,
400
401
  logger: LoggerOrName | None = None,
401
- errors: type[Exception] | tuple[type[Exception], ...] | None = None,
402
+ errors: ExceptionTypeLike[Exception] | None = None,
402
403
  sleep: Delta | None = None,
403
404
  ) -> bool:
404
405
  """Repeatedly call a coroutine until it succeeds."""
@@ -415,7 +416,7 @@ async def loop_until_succeed(
415
416
  case=[f"{exc_type=}", f"{exc_value=}"]
416
417
  ) from None
417
418
  sys.excepthook(exc_type, exc_value, traceback)
418
- if (errors is not None) and isinstance(error, errors):
419
+ if (errors is not None) and is_instance_error(error, errors):
419
420
  return False
420
421
  if sleep is not None:
421
422
  if logger is not None:
utilities/errors.py CHANGED
@@ -4,7 +4,7 @@ from dataclasses import dataclass
4
4
  from typing import TYPE_CHECKING, assert_never, override
5
5
 
6
6
  if TYPE_CHECKING:
7
- from utilities.types import MaybeType
7
+ from utilities.types import ExceptionTypeLike, MaybeType
8
8
 
9
9
 
10
10
  @dataclass(kw_only=True, slots=True)
@@ -21,6 +21,20 @@ class ImpossibleCaseError(Exception):
21
21
  ##
22
22
 
23
23
 
24
+ def is_instance_error(
25
+ error: BaseException, class_or_tuple: ExceptionTypeLike[Exception], /
26
+ ) -> bool:
27
+ """Check if an instance relationship holds, allowing for groups."""
28
+ if isinstance(error, class_or_tuple):
29
+ return True
30
+ if not isinstance(error, BaseExceptionGroup):
31
+ return False
32
+ return any(is_instance_error(e, class_or_tuple) for e in error.exceptions)
33
+
34
+
35
+ ##
36
+
37
+
24
38
  def repr_error(error: MaybeType[BaseException], /) -> str:
25
39
  """Get a string representation of an error."""
26
40
  match error:
@@ -36,4 +50,4 @@ def repr_error(error: MaybeType[BaseException], /) -> str:
36
50
  assert_never(never)
37
51
 
38
52
 
39
- __all__ = ["ImpossibleCaseError", "repr_error"]
53
+ __all__ = ["ImpossibleCaseError", "is_instance_error", "repr_error"]
utilities/types.py CHANGED
@@ -105,6 +105,10 @@ type MonthInt = Literal[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
105
105
  type EnumLike[E: Enum] = MaybeStr[E]
106
106
 
107
107
 
108
+ # errors
109
+ type ExceptionTypeLike[T: Exception] = type[T] | tuple[type[T], ...]
110
+
111
+
108
112
  # ipaddress
109
113
  IPv4AddressLike = MaybeStr[IPv4Address]
110
114
  IPv6AddressLike = MaybeStr[IPv6Address]
@@ -265,6 +269,7 @@ __all__ = [
265
269
  "Delta",
266
270
  "EnumLike",
267
271
  "ExcInfo",
272
+ "ExceptionTypeLike",
268
273
  "IPv4AddressLike",
269
274
  "IPv6AddressLike",
270
275
  "IterableHashable",