dycw-utilities 0.131.8__py3-none-any.whl → 0.131.10__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.131.8
3
+ Version: 0.131.10
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=7GFnOq-ksc-RNtwI9lMII4eofdNt78J6EbkJmHRGm6E,60
1
+ utilities/__init__.py,sha256=cONWlHZLOohX6BsePAlAXt2CKhMSrwzSki10hHq4rjw,61
2
2
  utilities/aiolimiter.py,sha256=mD0wEiqMgwpty4XTbawFpnkkmJS6R4JRsVXFUaoitSU,628
3
3
  utilities/altair.py,sha256=HeZBVUocjkrTNwwKrClppsIqgNFF-ykv05HfZSoHYno,9104
4
4
  utilities/asyncio.py,sha256=yfKvAIDCRrWdyQMVZMo4DJQx4nVrXoAcqwhNuF95Ryo,38186
@@ -61,7 +61,7 @@ utilities/pytest.py,sha256=zP4CWKXpRVk4aRDRxolUAvqQwX7wgDO8lzmkQfuZaZo,7832
61
61
  utilities/pytest_regressions.py,sha256=YI55B7EtLjhz7zPJZ6NK9bWrxrKCKabWZJe1cwcbA5o,5082
62
62
  utilities/python_dotenv.py,sha256=edXsvHZhZnYeqfMfrsRRpj7_9eJI6uizh3xLx8Q9B3w,3228
63
63
  utilities/random.py,sha256=lYdjgxB7GCfU_fwFVl5U-BIM_HV3q6_urL9byjrwDM8,4157
64
- utilities/re.py,sha256=5J4d8VwIPFVrX2Eb8zfoxImDv7IwiN_U7mJ07wR2Wvs,3958
64
+ utilities/re.py,sha256=J7pJOn-Zn5nJ6rvWwMeJWP86EtMk_klhBexnoSaQiZA,4610
65
65
  utilities/redis.py,sha256=IceT5EjgrebVkGL8X3M35xlqjI2c7zFbyV1P4dExN4M,36037
66
66
  utilities/reprlib.py,sha256=ssYTcBW-TeRh3fhCJv57sopTZHF5FrPyyUg9yp5XBlo,3953
67
67
  utilities/scipy.py,sha256=wZJM7fEgBAkLSYYvSmsg5ac-QuwAI0BGqHVetw1_Hb0,947
@@ -80,7 +80,7 @@ utilities/text.py,sha256=ymBFlP_cA8OgNnZRVNs7FAh7OG8HxE6YkiLEMZv5g_A,11297
80
80
  utilities/threading.py,sha256=GvBOp4CyhHfN90wGXZuA2VKe9fGzMaEa7oCl4f3nnPU,1009
81
81
  utilities/timer.py,sha256=VeSl3ot8-f4D1d3HjjSsgKvjxHJGXd_sW4KcTExOR64,2475
82
82
  utilities/traceback.py,sha256=l9onlqDdW5GCSIFbU_-htBE7KlsvsJdNtGrK6-k0RCQ,8759
83
- utilities/types.py,sha256=gP04CcCOyFrG7BgblVCsrrChiuO2x842NDVW-GF7odo,18370
83
+ utilities/types.py,sha256=Ubd3VBiqZ71eS71WSemHEM4oRF-5fnwd3PnMAm8IZaI,18461
84
84
  utilities/typing.py,sha256=kQWywPcRbFBKmvQBELmgbiqSHsnlo_D0ru53vl6KDeY,13846
85
85
  utilities/tzdata.py,sha256=yCf70NICwAeazN3_JcXhWvRqCy06XJNQ42j7r6gw3HY,1217
86
86
  utilities/tzlocal.py,sha256=P5BjqTiYskeCwjE7i9zycCFXO4MWdZgYCh4jut-LpzA,1042
@@ -91,7 +91,7 @@ utilities/whenever.py,sha256=jS31ZAY5OMxFxLja_Yo5Fidi87Pd-GoVZ7Vi_teqVDA,16743
91
91
  utilities/whenever2.py,sha256=JHixGl6KibK8GUF13GeBjvWMYsFHRDSXixSo0xMSJFM,5437
92
92
  utilities/zipfile.py,sha256=24lQc9ATcJxHXBPc_tBDiJk48pWyRrlxO2fIsFxU0A8,699
93
93
  utilities/zoneinfo.py,sha256=tvcgu3QzDxe2suTexi2QzRGpin7VK1TjHa0JYYxT69I,1862
94
- dycw_utilities-0.131.8.dist-info/METADATA,sha256=R5VRnHIlEDPgRLMdPF6PWrQ7VwJmzeWBUNpSVIrPTqA,1584
95
- dycw_utilities-0.131.8.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
96
- dycw_utilities-0.131.8.dist-info/licenses/LICENSE,sha256=gppZp16M6nSVpBbUBrNL6JuYfvKwZiKgV7XoKKsHzqo,1066
97
- dycw_utilities-0.131.8.dist-info/RECORD,,
94
+ dycw_utilities-0.131.10.dist-info/METADATA,sha256=-HOUsSw5_v1-mDFC9l1PXOLDdbSUCRRbZYCgf-nmnbY,1585
95
+ dycw_utilities-0.131.10.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
96
+ dycw_utilities-0.131.10.dist-info/licenses/LICENSE,sha256=gppZp16M6nSVpBbUBrNL6JuYfvKwZiKgV7XoKKsHzqo,1066
97
+ dycw_utilities-0.131.10.dist-info/RECORD,,
utilities/__init__.py CHANGED
@@ -1,3 +1,3 @@
1
1
  from __future__ import annotations
2
2
 
3
- __version__ = "0.131.8"
3
+ __version__ = "0.131.10"
utilities/re.py CHANGED
@@ -2,37 +2,59 @@ from __future__ import annotations
2
2
 
3
3
  import re
4
4
  from dataclasses import dataclass
5
- from typing import override
5
+ from re import Pattern
6
+ from typing import TYPE_CHECKING, assert_never, override
6
7
 
7
8
  from utilities.iterables import OneEmptyError, OneNonUniqueError, one
8
9
 
10
+ if TYPE_CHECKING:
11
+ from utilities.types import PatternLike
9
12
 
10
- def extract_group(pattern: str, text: str, /, *, flags: int = 0) -> str:
13
+
14
+ def ensure_pattern(pattern: PatternLike, /, *, flags: int = 0) -> Pattern[str]:
15
+ """Ensure a pattern is returned."""
16
+ match pattern:
17
+ case Pattern():
18
+ return pattern
19
+ case str():
20
+ return re.compile(pattern, flags=flags)
21
+ case _ as never:
22
+ assert_never(never)
23
+
24
+
25
+ ##
26
+
27
+
28
+ def extract_group(pattern: PatternLike, text: str, /, *, flags: int = 0) -> str:
11
29
  """Extract a group.
12
30
 
13
31
  The regex must have 1 capture group, and this must match exactly once.
14
32
  """
15
- compiled = re.compile(pattern, flags=flags)
16
- match compiled.groups:
33
+ pattern_use = ensure_pattern(pattern, flags=flags)
34
+ match pattern_use.groups:
17
35
  case 0:
18
- raise _ExtractGroupNoCaptureGroupsError(pattern=pattern, text=text)
36
+ raise _ExtractGroupNoCaptureGroupsError(pattern=pattern_use, text=text)
19
37
  case 1:
20
- matches: list[str] = compiled.findall(text)
38
+ matches: list[str] = pattern_use.findall(text)
21
39
  try:
22
40
  return one(matches)
23
41
  except OneEmptyError:
24
- raise _ExtractGroupNoMatchesError(pattern=pattern, text=text) from None
42
+ raise _ExtractGroupNoMatchesError(
43
+ pattern=pattern_use, text=text
44
+ ) from None
25
45
  except OneNonUniqueError:
26
46
  raise _ExtractGroupMultipleMatchesError(
27
- pattern=pattern, text=text, matches=matches
47
+ pattern=pattern_use, text=text, matches=matches
28
48
  ) from None
29
49
  case _:
30
- raise _ExtractGroupMultipleCaptureGroupsError(pattern=pattern, text=text)
50
+ raise _ExtractGroupMultipleCaptureGroupsError(
51
+ pattern=pattern_use, text=text
52
+ )
31
53
 
32
54
 
33
55
  @dataclass(kw_only=True, slots=True)
34
56
  class ExtractGroupError(Exception):
35
- pattern: str
57
+ pattern: Pattern[str]
36
58
  text: str
37
59
 
38
60
 
@@ -68,32 +90,35 @@ class _ExtractGroupNoMatchesError(ExtractGroupError):
68
90
  return f"Pattern {self.pattern} must match against {self.text}"
69
91
 
70
92
 
71
- def extract_groups(pattern: str, text: str, /, *, flags: int = 0) -> list[str]:
93
+ ##
94
+
95
+
96
+ def extract_groups(pattern: PatternLike, text: str, /, *, flags: int = 0) -> list[str]:
72
97
  """Extract multiple groups.
73
98
 
74
99
  The regex may have any number of capture groups, and they must collectively
75
100
  match exactly once.
76
101
  """
77
- compiled = re.compile(pattern, flags=flags)
78
- if (n_groups := compiled.groups) == 0:
79
- raise _ExtractGroupsNoCaptureGroupsError(pattern=pattern, text=text)
80
- matches: list[str] = compiled.findall(text)
102
+ pattern_use = ensure_pattern(pattern, flags=flags)
103
+ if (n_groups := pattern_use.groups) == 0:
104
+ raise _ExtractGroupsNoCaptureGroupsError(pattern=pattern_use, text=text)
105
+ matches: list[str] = pattern_use.findall(text)
81
106
  match len(matches), n_groups:
82
107
  case 0, _:
83
- raise _ExtractGroupsNoMatchesError(pattern=pattern, text=text)
108
+ raise _ExtractGroupsNoMatchesError(pattern=pattern_use, text=text)
84
109
  case 1, 1:
85
110
  return matches
86
111
  case 1, _:
87
112
  return list(one(matches))
88
113
  case _:
89
114
  raise _ExtractGroupsMultipleMatchesError(
90
- pattern=pattern, text=text, matches=matches
115
+ pattern=pattern_use, text=text, matches=matches
91
116
  )
92
117
 
93
118
 
94
119
  @dataclass(kw_only=True, slots=True)
95
120
  class ExtractGroupsError(Exception):
96
- pattern: str
121
+ pattern: Pattern[str]
97
122
  text: str
98
123
 
99
124
 
@@ -108,7 +133,7 @@ class _ExtractGroupsMultipleMatchesError(ExtractGroupsError):
108
133
 
109
134
  @dataclass(kw_only=True, slots=True)
110
135
  class _ExtractGroupsNoCaptureGroupsError(ExtractGroupsError):
111
- pattern: str
136
+ pattern: Pattern[str]
112
137
  text: str
113
138
 
114
139
  @override
@@ -123,4 +148,10 @@ class _ExtractGroupsNoMatchesError(ExtractGroupsError):
123
148
  return f"Pattern {self.pattern} must match against {self.text}"
124
149
 
125
150
 
126
- __all__ = ["ExtractGroupError", "ExtractGroupsError", "extract_group", "extract_groups"]
151
+ __all__ = [
152
+ "ExtractGroupError",
153
+ "ExtractGroupsError",
154
+ "ensure_pattern",
155
+ "extract_group",
156
+ "extract_groups",
157
+ ]
utilities/types.py CHANGED
@@ -7,6 +7,7 @@ from enum import Enum
7
7
  from logging import Logger
8
8
  from pathlib import Path
9
9
  from random import Random
10
+ from re import Pattern
10
11
  from types import TracebackType
11
12
  from typing import (
12
13
  Any,
@@ -249,6 +250,10 @@ type PathLike = MaybeStr[Path]
249
250
  type Seed = int | float | str | bytes | bytearray | Random
250
251
 
251
252
 
253
+ # re
254
+ type PatternLike = MaybeStr[Pattern[str]]
255
+
256
+
252
257
  # traceback
253
258
  type ExcInfo = tuple[type[BaseException], BaseException, TracebackType]
254
259
  type OptExcInfo = ExcInfo | tuple[None, None, None]
@@ -294,6 +299,7 @@ __all__ = [
294
299
  "Parallelism",
295
300
  "ParseObjectExtra",
296
301
  "PathLike",
302
+ "PatternLike",
297
303
  "RoundMode",
298
304
  "Seed",
299
305
  "SerializeObjectExtra",