dycw-utilities 0.129.10__py3-none-any.whl → 0.175.17__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.175.17.dist-info/METADATA +34 -0
- dycw_utilities-0.175.17.dist-info/RECORD +103 -0
- dycw_utilities-0.175.17.dist-info/WHEEL +4 -0
- dycw_utilities-0.175.17.dist-info/entry_points.txt +4 -0
- utilities/__init__.py +1 -1
- utilities/altair.py +14 -14
- utilities/asyncio.py +350 -819
- utilities/atomicwrites.py +18 -6
- utilities/atools.py +77 -22
- utilities/cachetools.py +24 -29
- utilities/click.py +393 -237
- utilities/concurrent.py +8 -11
- utilities/contextlib.py +216 -17
- utilities/contextvars.py +20 -1
- utilities/cryptography.py +3 -3
- utilities/dataclasses.py +83 -118
- utilities/docker.py +293 -0
- utilities/enum.py +26 -23
- utilities/errors.py +17 -3
- utilities/fastapi.py +29 -65
- utilities/fpdf2.py +3 -3
- utilities/functions.py +169 -416
- utilities/functools.py +18 -19
- utilities/git.py +9 -30
- utilities/grp.py +28 -0
- utilities/gzip.py +31 -0
- utilities/http.py +3 -2
- utilities/hypothesis.py +738 -589
- utilities/importlib.py +17 -1
- utilities/inflect.py +25 -0
- utilities/iterables.py +194 -262
- utilities/jinja2.py +148 -0
- utilities/json.py +70 -0
- utilities/libcst.py +38 -17
- utilities/lightweight_charts.py +5 -9
- utilities/logging.py +345 -543
- utilities/math.py +18 -13
- utilities/memory_profiler.py +11 -15
- utilities/more_itertools.py +200 -131
- utilities/operator.py +33 -29
- utilities/optuna.py +6 -6
- utilities/orjson.py +272 -137
- utilities/os.py +61 -4
- utilities/parse.py +59 -61
- utilities/pathlib.py +281 -40
- utilities/permissions.py +298 -0
- utilities/pickle.py +2 -2
- utilities/platform.py +24 -5
- utilities/polars.py +1214 -430
- utilities/polars_ols.py +1 -1
- utilities/postgres.py +408 -0
- utilities/pottery.py +113 -26
- utilities/pqdm.py +10 -11
- utilities/psutil.py +6 -57
- utilities/pwd.py +28 -0
- utilities/pydantic.py +4 -54
- utilities/pydantic_settings.py +240 -0
- utilities/pydantic_settings_sops.py +76 -0
- utilities/pyinstrument.py +8 -10
- utilities/pytest.py +227 -121
- utilities/pytest_plugins/__init__.py +1 -0
- utilities/pytest_plugins/pytest_randomly.py +23 -0
- utilities/pytest_plugins/pytest_regressions.py +56 -0
- utilities/pytest_regressions.py +26 -46
- utilities/random.py +13 -9
- utilities/re.py +58 -28
- utilities/redis.py +401 -550
- utilities/scipy.py +1 -1
- utilities/sentinel.py +10 -0
- utilities/shelve.py +4 -1
- utilities/shutil.py +25 -0
- utilities/slack_sdk.py +36 -106
- utilities/sqlalchemy.py +502 -473
- utilities/sqlalchemy_polars.py +38 -94
- utilities/string.py +2 -3
- utilities/subprocess.py +1572 -0
- utilities/tempfile.py +86 -4
- utilities/testbook.py +50 -0
- utilities/text.py +165 -42
- utilities/timer.py +37 -65
- utilities/traceback.py +158 -929
- utilities/types.py +146 -116
- utilities/typing.py +531 -71
- utilities/tzdata.py +1 -53
- utilities/tzlocal.py +6 -23
- utilities/uuid.py +43 -5
- utilities/version.py +27 -26
- utilities/whenever.py +1776 -386
- utilities/zoneinfo.py +84 -22
- dycw_utilities-0.129.10.dist-info/METADATA +0 -241
- dycw_utilities-0.129.10.dist-info/RECORD +0 -96
- dycw_utilities-0.129.10.dist-info/WHEEL +0 -4
- dycw_utilities-0.129.10.dist-info/licenses/LICENSE +0 -21
- utilities/datetime.py +0 -1409
- utilities/eventkit.py +0 -402
- utilities/loguru.py +0 -144
- utilities/luigi.py +0 -228
- utilities/period.py +0 -324
- utilities/pyrsistent.py +0 -89
- utilities/python_dotenv.py +0 -105
- utilities/streamlit.py +0 -105
- utilities/sys.py +0 -87
- utilities/tenacity.py +0 -145
utilities/random.py
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
from random import Random, SystemRandom
|
|
4
|
-
from typing import TYPE_CHECKING
|
|
4
|
+
from typing import TYPE_CHECKING
|
|
5
|
+
|
|
6
|
+
from utilities.functools import cache
|
|
5
7
|
|
|
6
8
|
if TYPE_CHECKING:
|
|
7
9
|
from collections.abc import Iterable
|
|
@@ -9,7 +11,6 @@ if TYPE_CHECKING:
|
|
|
9
11
|
from utilities.types import Seed
|
|
10
12
|
|
|
11
13
|
|
|
12
|
-
_T = TypeVar("_T")
|
|
13
14
|
SYSTEM_RANDOM = SystemRandom()
|
|
14
15
|
|
|
15
16
|
|
|
@@ -18,16 +19,16 @@ SYSTEM_RANDOM = SystemRandom()
|
|
|
18
19
|
|
|
19
20
|
def bernoulli(*, true: float = 0.5, seed: Seed | None = None) -> bool:
|
|
20
21
|
"""Return a Bernoulli random variate."""
|
|
21
|
-
|
|
22
|
-
return bool(
|
|
22
|
+
state = get_state(seed)
|
|
23
|
+
return bool(state.binomialvariate(p=true))
|
|
23
24
|
|
|
24
25
|
|
|
25
26
|
##
|
|
26
27
|
|
|
27
28
|
|
|
28
|
-
def get_docker_name(
|
|
29
|
+
def get_docker_name(seed: Seed | None = None, /) -> str:
|
|
29
30
|
"""Get a docker name."""
|
|
30
|
-
state = get_state(seed
|
|
31
|
+
state = get_state(seed)
|
|
31
32
|
prefix = state.choice(_DOCKER_PREFIXES)
|
|
32
33
|
suffix = state.choice(_DOCKER_SUFFIXES)
|
|
33
34
|
digit = state.randint(0, 9)
|
|
@@ -48,16 +49,19 @@ _DOCKER_SUFFIXES = [
|
|
|
48
49
|
##
|
|
49
50
|
|
|
50
51
|
|
|
51
|
-
|
|
52
|
+
@cache
|
|
53
|
+
def get_state(seed: Seed | None = None, /) -> Random:
|
|
52
54
|
"""Get a random state."""
|
|
53
55
|
return seed if isinstance(seed, Random) else Random(x=seed)
|
|
54
56
|
|
|
55
57
|
|
|
56
58
|
##
|
|
57
|
-
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def shuffle[T](iterable: Iterable[T], /, *, seed: Seed | None = None) -> list[T]:
|
|
58
62
|
"""Shuffle an iterable."""
|
|
59
63
|
copy = list(iterable).copy()
|
|
60
|
-
state = get_state(seed
|
|
64
|
+
state = get_state(seed)
|
|
61
65
|
state.shuffle(copy)
|
|
62
66
|
return copy
|
|
63
67
|
|
utilities/re.py
CHANGED
|
@@ -2,37 +2,58 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import re
|
|
4
4
|
from dataclasses import dataclass
|
|
5
|
-
from
|
|
5
|
+
from re import Pattern
|
|
6
|
+
from typing import TYPE_CHECKING, assert_never, override
|
|
6
7
|
|
|
7
|
-
|
|
8
|
+
if TYPE_CHECKING:
|
|
9
|
+
from utilities.types import PatternLike
|
|
8
10
|
|
|
9
11
|
|
|
10
|
-
def
|
|
12
|
+
def ensure_pattern(pattern: PatternLike, /, *, flags: int = 0) -> Pattern[str]:
|
|
13
|
+
"""Ensure a pattern is returned."""
|
|
14
|
+
match pattern:
|
|
15
|
+
case Pattern():
|
|
16
|
+
return pattern
|
|
17
|
+
case str():
|
|
18
|
+
return re.compile(pattern, flags=flags)
|
|
19
|
+
case never:
|
|
20
|
+
assert_never(never)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
##
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def extract_group(pattern: PatternLike, text: str, /, *, flags: int = 0) -> str:
|
|
11
27
|
"""Extract a group.
|
|
12
28
|
|
|
13
29
|
The regex must have 1 capture group, and this must match exactly once.
|
|
14
30
|
"""
|
|
15
|
-
|
|
16
|
-
match
|
|
31
|
+
pattern_use = ensure_pattern(pattern, flags=flags)
|
|
32
|
+
match pattern_use.groups:
|
|
17
33
|
case 0:
|
|
18
|
-
raise _ExtractGroupNoCaptureGroupsError(pattern=
|
|
34
|
+
raise _ExtractGroupNoCaptureGroupsError(pattern=pattern_use, text=text)
|
|
19
35
|
case 1:
|
|
20
|
-
matches: list[str] =
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
36
|
+
matches: list[str] = pattern_use.findall(text)
|
|
37
|
+
match len(matches):
|
|
38
|
+
case 0:
|
|
39
|
+
raise _ExtractGroupNoMatchesError(
|
|
40
|
+
pattern=pattern_use, text=text
|
|
41
|
+
) from None
|
|
42
|
+
case 1:
|
|
43
|
+
return matches[0]
|
|
44
|
+
case _:
|
|
45
|
+
raise _ExtractGroupMultipleMatchesError(
|
|
46
|
+
pattern=pattern_use, text=text, matches=matches
|
|
47
|
+
) from None
|
|
29
48
|
case _:
|
|
30
|
-
raise _ExtractGroupMultipleCaptureGroupsError(
|
|
49
|
+
raise _ExtractGroupMultipleCaptureGroupsError(
|
|
50
|
+
pattern=pattern_use, text=text
|
|
51
|
+
)
|
|
31
52
|
|
|
32
53
|
|
|
33
54
|
@dataclass(kw_only=True, slots=True)
|
|
34
55
|
class ExtractGroupError(Exception):
|
|
35
|
-
pattern: str
|
|
56
|
+
pattern: Pattern[str]
|
|
36
57
|
text: str
|
|
37
58
|
|
|
38
59
|
|
|
@@ -68,32 +89,35 @@ class _ExtractGroupNoMatchesError(ExtractGroupError):
|
|
|
68
89
|
return f"Pattern {self.pattern} must match against {self.text}"
|
|
69
90
|
|
|
70
91
|
|
|
71
|
-
|
|
92
|
+
##
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def extract_groups(pattern: PatternLike, text: str, /, *, flags: int = 0) -> list[str]:
|
|
72
96
|
"""Extract multiple groups.
|
|
73
97
|
|
|
74
98
|
The regex may have any number of capture groups, and they must collectively
|
|
75
99
|
match exactly once.
|
|
76
100
|
"""
|
|
77
|
-
|
|
78
|
-
if (n_groups :=
|
|
79
|
-
raise _ExtractGroupsNoCaptureGroupsError(pattern=
|
|
80
|
-
matches: list[str] =
|
|
101
|
+
pattern_use = ensure_pattern(pattern, flags=flags)
|
|
102
|
+
if (n_groups := pattern_use.groups) == 0:
|
|
103
|
+
raise _ExtractGroupsNoCaptureGroupsError(pattern=pattern_use, text=text)
|
|
104
|
+
matches: list[str] = pattern_use.findall(text)
|
|
81
105
|
match len(matches), n_groups:
|
|
82
106
|
case 0, _:
|
|
83
|
-
raise _ExtractGroupsNoMatchesError(pattern=
|
|
107
|
+
raise _ExtractGroupsNoMatchesError(pattern=pattern_use, text=text)
|
|
84
108
|
case 1, 1:
|
|
85
109
|
return matches
|
|
86
110
|
case 1, _:
|
|
87
|
-
return list(
|
|
111
|
+
return list(matches[0])
|
|
88
112
|
case _:
|
|
89
113
|
raise _ExtractGroupsMultipleMatchesError(
|
|
90
|
-
pattern=
|
|
114
|
+
pattern=pattern_use, text=text, matches=matches
|
|
91
115
|
)
|
|
92
116
|
|
|
93
117
|
|
|
94
118
|
@dataclass(kw_only=True, slots=True)
|
|
95
119
|
class ExtractGroupsError(Exception):
|
|
96
|
-
pattern: str
|
|
120
|
+
pattern: Pattern[str]
|
|
97
121
|
text: str
|
|
98
122
|
|
|
99
123
|
|
|
@@ -108,7 +132,7 @@ class _ExtractGroupsMultipleMatchesError(ExtractGroupsError):
|
|
|
108
132
|
|
|
109
133
|
@dataclass(kw_only=True, slots=True)
|
|
110
134
|
class _ExtractGroupsNoCaptureGroupsError(ExtractGroupsError):
|
|
111
|
-
pattern: str
|
|
135
|
+
pattern: Pattern[str]
|
|
112
136
|
text: str
|
|
113
137
|
|
|
114
138
|
@override
|
|
@@ -123,4 +147,10 @@ class _ExtractGroupsNoMatchesError(ExtractGroupsError):
|
|
|
123
147
|
return f"Pattern {self.pattern} must match against {self.text}"
|
|
124
148
|
|
|
125
149
|
|
|
126
|
-
__all__ = [
|
|
150
|
+
__all__ = [
|
|
151
|
+
"ExtractGroupError",
|
|
152
|
+
"ExtractGroupsError",
|
|
153
|
+
"ensure_pattern",
|
|
154
|
+
"extract_group",
|
|
155
|
+
"extract_groups",
|
|
156
|
+
]
|