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/hypothesis.py
CHANGED
|
@@ -4,26 +4,16 @@ import builtins
|
|
|
4
4
|
import datetime as dt
|
|
5
5
|
from contextlib import contextmanager
|
|
6
6
|
from dataclasses import dataclass
|
|
7
|
-
from datetime import timezone
|
|
8
7
|
from enum import Enum, auto
|
|
9
|
-
from functools import partial
|
|
10
8
|
from math import ceil, floor, inf, isclose, isfinite, nan
|
|
11
9
|
from os import environ
|
|
12
10
|
from pathlib import Path
|
|
13
11
|
from re import search
|
|
14
12
|
from string import ascii_letters, ascii_lowercase, ascii_uppercase, digits, printable
|
|
15
13
|
from subprocess import check_call
|
|
16
|
-
from typing import
|
|
17
|
-
TYPE_CHECKING,
|
|
18
|
-
Any,
|
|
19
|
-
Literal,
|
|
20
|
-
TypeVar,
|
|
21
|
-
assert_never,
|
|
22
|
-
cast,
|
|
23
|
-
overload,
|
|
24
|
-
override,
|
|
25
|
-
)
|
|
14
|
+
from typing import TYPE_CHECKING, Any, Literal, assert_never, cast, overload, override
|
|
26
15
|
|
|
16
|
+
import hypothesis.strategies
|
|
27
17
|
from hypothesis import HealthCheck, Phase, Verbosity, assume, settings
|
|
28
18
|
from hypothesis.errors import InvalidArgument
|
|
29
19
|
from hypothesis.strategies import (
|
|
@@ -33,7 +23,6 @@ from hypothesis.strategies import (
|
|
|
33
23
|
booleans,
|
|
34
24
|
characters,
|
|
35
25
|
composite,
|
|
36
|
-
dates,
|
|
37
26
|
datetimes,
|
|
38
27
|
floats,
|
|
39
28
|
integers,
|
|
@@ -43,67 +32,93 @@ from hypothesis.strategies import (
|
|
|
43
32
|
sampled_from,
|
|
44
33
|
sets,
|
|
45
34
|
text,
|
|
46
|
-
|
|
35
|
+
timezones,
|
|
47
36
|
uuids,
|
|
48
37
|
)
|
|
49
38
|
from hypothesis.utils.conventions import not_set
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
date_duration_to_timedelta,
|
|
64
|
-
date_to_month,
|
|
65
|
-
datetime_duration_to_float,
|
|
66
|
-
datetime_duration_to_timedelta,
|
|
67
|
-
round_datetime,
|
|
39
|
+
from whenever import (
|
|
40
|
+
Date,
|
|
41
|
+
DateDelta,
|
|
42
|
+
DateTimeDelta,
|
|
43
|
+
MonthDay,
|
|
44
|
+
PlainDateTime,
|
|
45
|
+
RepeatedTime,
|
|
46
|
+
SkippedTime,
|
|
47
|
+
Time,
|
|
48
|
+
TimeDelta,
|
|
49
|
+
TimeZoneNotFoundError,
|
|
50
|
+
YearMonth,
|
|
51
|
+
ZonedDateTime,
|
|
68
52
|
)
|
|
53
|
+
|
|
69
54
|
from utilities.functions import ensure_int, ensure_str, max_nullable, min_nullable
|
|
70
55
|
from utilities.math import (
|
|
71
56
|
MAX_FLOAT32,
|
|
72
57
|
MAX_FLOAT64,
|
|
58
|
+
MAX_INT8,
|
|
59
|
+
MAX_INT16,
|
|
73
60
|
MAX_INT32,
|
|
74
61
|
MAX_INT64,
|
|
62
|
+
MAX_UINT8,
|
|
63
|
+
MAX_UINT16,
|
|
75
64
|
MAX_UINT32,
|
|
76
65
|
MAX_UINT64,
|
|
77
66
|
MIN_FLOAT32,
|
|
78
67
|
MIN_FLOAT64,
|
|
68
|
+
MIN_INT8,
|
|
69
|
+
MIN_INT16,
|
|
79
70
|
MIN_INT32,
|
|
80
71
|
MIN_INT64,
|
|
72
|
+
MIN_UINT8,
|
|
73
|
+
MIN_UINT16,
|
|
81
74
|
MIN_UINT32,
|
|
82
75
|
MIN_UINT64,
|
|
83
76
|
is_zero,
|
|
84
77
|
)
|
|
85
78
|
from utilities.os import get_env_var
|
|
86
|
-
from utilities.pathlib import temp_cwd
|
|
87
|
-
from utilities.
|
|
88
|
-
from utilities.
|
|
79
|
+
from utilities.pathlib import module_path, temp_cwd
|
|
80
|
+
from utilities.permissions import Permissions
|
|
81
|
+
from utilities.platform import IS_LINUX
|
|
82
|
+
from utilities.sentinel import Sentinel, is_sentinel, sentinel
|
|
89
83
|
from utilities.tempfile import TEMP_DIR, TemporaryDirectory
|
|
90
84
|
from utilities.version import Version
|
|
91
|
-
from utilities.
|
|
85
|
+
from utilities.whenever import (
|
|
86
|
+
DATE_DELTA_MAX,
|
|
87
|
+
DATE_DELTA_MIN,
|
|
88
|
+
DATE_DELTA_PARSABLE_MAX,
|
|
89
|
+
DATE_DELTA_PARSABLE_MIN,
|
|
90
|
+
DATE_TIME_DELTA_MAX,
|
|
91
|
+
DATE_TIME_DELTA_MIN,
|
|
92
|
+
DATE_TIME_DELTA_PARSABLE_MAX,
|
|
93
|
+
DATE_TIME_DELTA_PARSABLE_MIN,
|
|
94
|
+
DATE_TWO_DIGIT_YEAR_MAX,
|
|
95
|
+
DATE_TWO_DIGIT_YEAR_MIN,
|
|
96
|
+
DAY,
|
|
97
|
+
TIME_DELTA_MAX,
|
|
98
|
+
TIME_DELTA_MIN,
|
|
99
|
+
DatePeriod,
|
|
100
|
+
TimePeriod,
|
|
101
|
+
ZonedDateTimePeriod,
|
|
102
|
+
get_now,
|
|
103
|
+
to_date_time_delta,
|
|
104
|
+
to_days,
|
|
105
|
+
to_nanoseconds,
|
|
106
|
+
)
|
|
107
|
+
from utilities.zoneinfo import UTC, to_zone_info
|
|
92
108
|
|
|
93
109
|
if TYPE_CHECKING:
|
|
94
|
-
from collections.abc import Collection, Hashable, Iterable, Iterator
|
|
110
|
+
from collections.abc import Collection, Hashable, Iterable, Iterator
|
|
95
111
|
from zoneinfo import ZoneInfo
|
|
96
112
|
|
|
97
113
|
from hypothesis.database import ExampleDatabase
|
|
114
|
+
from libcst import Import, ImportFrom
|
|
98
115
|
from numpy.random import RandomState
|
|
99
|
-
from sqlalchemy
|
|
116
|
+
from sqlalchemy import URL
|
|
100
117
|
|
|
101
118
|
from utilities.numpy import NDArrayB, NDArrayF, NDArrayI, NDArrayO
|
|
102
|
-
from utilities.
|
|
103
|
-
from utilities.types import Duration, Number, RoundMode
|
|
119
|
+
from utilities.types import Number, TimeZone, TimeZoneLike
|
|
104
120
|
|
|
105
121
|
|
|
106
|
-
_T = TypeVar("_T")
|
|
107
122
|
type MaybeSearchStrategy[_T] = _T | SearchStrategy[_T]
|
|
108
123
|
type Shape = int | tuple[int, ...]
|
|
109
124
|
|
|
@@ -161,175 +176,184 @@ def bool_arrays(
|
|
|
161
176
|
|
|
162
177
|
|
|
163
178
|
@composite
|
|
164
|
-
def
|
|
179
|
+
def date_deltas(
|
|
165
180
|
draw: DrawFn,
|
|
166
181
|
/,
|
|
167
182
|
*,
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
)
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
max_parts.append(MAX_SERIALIZABLE_TIMEDELTA)
|
|
196
|
-
max_timedelta_use = min_nullable(max_parts)
|
|
197
|
-
_ = assume(min_timedelta_use <= max_timedelta_use)
|
|
198
|
-
st_timedeltas = (
|
|
199
|
-
timedeltas(min_value=min_timedelta_use, max_value=max_timedelta_use)
|
|
200
|
-
.map(_round_timedelta)
|
|
201
|
-
.filter(
|
|
202
|
-
partial(
|
|
203
|
-
_is_between_timedelta, min_=min_timedelta_use, max_=max_timedelta_use
|
|
204
|
-
)
|
|
205
|
-
)
|
|
206
|
-
)
|
|
207
|
-
st_integers = st_timedeltas.map(date_duration_to_int)
|
|
208
|
-
st_floats = st_integers.map(float)
|
|
209
|
-
return draw(st_integers | st_floats | st_timedeltas)
|
|
183
|
+
min_value: MaybeSearchStrategy[DateDelta | None] = None,
|
|
184
|
+
max_value: MaybeSearchStrategy[DateDelta | None] = None,
|
|
185
|
+
parsable: MaybeSearchStrategy[bool] = False,
|
|
186
|
+
) -> DateDelta:
|
|
187
|
+
"""Strategy for generating date deltas."""
|
|
188
|
+
min_value_, max_value_ = [draw2(draw, v) for v in [min_value, max_value]]
|
|
189
|
+
match min_value_:
|
|
190
|
+
case None:
|
|
191
|
+
min_value_ = DATE_DELTA_MIN
|
|
192
|
+
case DateDelta():
|
|
193
|
+
...
|
|
194
|
+
case never:
|
|
195
|
+
assert_never(never)
|
|
196
|
+
match max_value_:
|
|
197
|
+
case None:
|
|
198
|
+
max_value_ = DATE_DELTA_MAX
|
|
199
|
+
case DateDelta():
|
|
200
|
+
...
|
|
201
|
+
case never:
|
|
202
|
+
assert_never(never)
|
|
203
|
+
min_days = to_days(min_value_)
|
|
204
|
+
max_days = to_days(max_value_)
|
|
205
|
+
if draw2(draw, parsable):
|
|
206
|
+
min_days = max(min_days, to_days(DATE_DELTA_PARSABLE_MIN))
|
|
207
|
+
max_days = min(max_days, to_days(DATE_DELTA_PARSABLE_MAX))
|
|
208
|
+
days = draw(integers(min_value=min_days, max_value=max_days))
|
|
209
|
+
return DateDelta(days=days)
|
|
210
210
|
|
|
211
211
|
|
|
212
|
-
|
|
213
|
-
return dt.timedelta(days=timedelta.days)
|
|
212
|
+
##
|
|
214
213
|
|
|
215
214
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
215
|
+
@composite
|
|
216
|
+
def date_periods(
|
|
217
|
+
draw: DrawFn,
|
|
218
|
+
/,
|
|
219
|
+
*,
|
|
220
|
+
min_value: MaybeSearchStrategy[Date | None] = None,
|
|
221
|
+
max_value: MaybeSearchStrategy[Date | None] = None,
|
|
222
|
+
two_digit: MaybeSearchStrategy[bool] = False,
|
|
223
|
+
) -> DatePeriod:
|
|
224
|
+
"""Strategy for generating date periods."""
|
|
225
|
+
min_value_, max_value_ = [draw2(draw, v) for v in [min_value, max_value]]
|
|
226
|
+
two_digit_ = draw2(draw, two_digit)
|
|
227
|
+
strategy = dates(min_value=min_value_, max_value=max_value_, two_digit=two_digit_)
|
|
228
|
+
start, end = draw(pairs(strategy, sorted=True))
|
|
229
|
+
return DatePeriod(start, end)
|
|
220
230
|
|
|
221
231
|
|
|
222
232
|
##
|
|
223
233
|
|
|
224
234
|
|
|
225
235
|
@composite
|
|
226
|
-
def
|
|
236
|
+
def date_time_deltas(
|
|
227
237
|
draw: DrawFn,
|
|
228
238
|
/,
|
|
229
239
|
*,
|
|
230
|
-
min_value: MaybeSearchStrategy[
|
|
231
|
-
max_value: MaybeSearchStrategy[
|
|
232
|
-
|
|
233
|
-
|
|
240
|
+
min_value: MaybeSearchStrategy[DateTimeDelta | None] = None,
|
|
241
|
+
max_value: MaybeSearchStrategy[DateTimeDelta | None] = None,
|
|
242
|
+
parsable: MaybeSearchStrategy[bool] = False,
|
|
243
|
+
nativable: MaybeSearchStrategy[bool] = False,
|
|
244
|
+
) -> DateTimeDelta:
|
|
245
|
+
"""Strategy for generating date deltas."""
|
|
234
246
|
min_value_, max_value_ = [draw2(draw, v) for v in [min_value, max_value]]
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
247
|
+
match min_value_:
|
|
248
|
+
case None:
|
|
249
|
+
min_value_ = DATE_TIME_DELTA_MIN
|
|
250
|
+
case DateTimeDelta():
|
|
251
|
+
...
|
|
252
|
+
case never:
|
|
253
|
+
assert_never(never)
|
|
254
|
+
match max_value_:
|
|
255
|
+
case None:
|
|
256
|
+
max_value_ = DATE_TIME_DELTA_MAX
|
|
257
|
+
case DateTimeDelta():
|
|
258
|
+
...
|
|
259
|
+
case never:
|
|
260
|
+
assert_never(never)
|
|
261
|
+
min_nanos, max_nanos = map(to_nanoseconds, [min_value_, max_value_])
|
|
262
|
+
if draw2(draw, parsable):
|
|
263
|
+
min_nanos = max(min_nanos, to_nanoseconds(DATE_TIME_DELTA_PARSABLE_MIN))
|
|
264
|
+
max_nanos = min(max_nanos, to_nanoseconds(DATE_TIME_DELTA_PARSABLE_MAX))
|
|
265
|
+
if draw2(draw, nativable):
|
|
266
|
+
min_micros, _ = divmod(min_nanos, 1000)
|
|
267
|
+
max_micros, _ = divmod(max_nanos, 1000)
|
|
268
|
+
micros = draw(integers(min_value=min_micros + 1, max_value=max_micros))
|
|
269
|
+
nanos = 1000 * micros
|
|
270
|
+
else:
|
|
271
|
+
nanos = draw(integers(min_value=min_nanos, max_value=max_nanos))
|
|
272
|
+
return to_date_time_delta(nanos)
|
|
238
273
|
|
|
239
274
|
|
|
240
275
|
##
|
|
241
276
|
|
|
242
277
|
|
|
243
278
|
@composite
|
|
244
|
-
def
|
|
279
|
+
def dates(
|
|
245
280
|
draw: DrawFn,
|
|
246
281
|
/,
|
|
247
282
|
*,
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
)
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
max_parts.append(MAX_SERIALIZABLE_TIMEDELTA)
|
|
276
|
-
max_timedelta_use = min_nullable(max_parts)
|
|
277
|
-
_ = assume(min_timedelta_use <= max_timedelta_use)
|
|
278
|
-
min_float_use, max_float_use = map(
|
|
279
|
-
datetime_duration_to_float, [min_timedelta_use, max_timedelta_use]
|
|
280
|
-
)
|
|
281
|
-
_ = assume(min_float_use <= max_float_use)
|
|
282
|
-
st_numbers = numbers(min_value=min_float_use, max_value=max_float_use)
|
|
283
|
-
st_timedeltas = timedeltas(min_value=min_timedelta_use, max_value=max_timedelta_use)
|
|
284
|
-
return draw(st_numbers | st_timedeltas)
|
|
283
|
+
min_value: MaybeSearchStrategy[Date | None] = None,
|
|
284
|
+
max_value: MaybeSearchStrategy[Date | None] = None,
|
|
285
|
+
two_digit: MaybeSearchStrategy[bool] = False,
|
|
286
|
+
) -> Date:
|
|
287
|
+
"""Strategy for generating dates."""
|
|
288
|
+
min_value_, max_value_ = [draw2(draw, v) for v in [min_value, max_value]]
|
|
289
|
+
match min_value_:
|
|
290
|
+
case None:
|
|
291
|
+
min_value_ = Date.MIN
|
|
292
|
+
case Date():
|
|
293
|
+
...
|
|
294
|
+
case never:
|
|
295
|
+
assert_never(never)
|
|
296
|
+
match max_value_:
|
|
297
|
+
case None:
|
|
298
|
+
max_value_ = Date.MAX
|
|
299
|
+
case Date():
|
|
300
|
+
...
|
|
301
|
+
case never:
|
|
302
|
+
assert_never(never)
|
|
303
|
+
if draw2(draw, two_digit):
|
|
304
|
+
min_value_ = max(min_value_, DATE_TWO_DIGIT_YEAR_MIN)
|
|
305
|
+
max_value_ = min(max_value_, DATE_TWO_DIGIT_YEAR_MAX)
|
|
306
|
+
min_date, max_date = [d.py_date() for d in [min_value_, max_value_]]
|
|
307
|
+
py_date = draw(hypothesis.strategies.dates(min_value=min_date, max_value=max_date))
|
|
308
|
+
return Date.from_py_date(py_date)
|
|
285
309
|
|
|
286
310
|
|
|
287
311
|
##
|
|
288
312
|
|
|
289
313
|
|
|
290
314
|
@overload
|
|
291
|
-
def draw2(
|
|
315
|
+
def draw2[T](
|
|
292
316
|
data_or_draw: DataObject | DrawFn,
|
|
293
|
-
maybe_strategy: MaybeSearchStrategy[
|
|
317
|
+
maybe_strategy: MaybeSearchStrategy[T],
|
|
294
318
|
/,
|
|
295
319
|
*,
|
|
296
320
|
sentinel: bool = False,
|
|
297
|
-
) ->
|
|
321
|
+
) -> T: ...
|
|
298
322
|
@overload
|
|
299
|
-
def draw2(
|
|
323
|
+
def draw2[T](
|
|
300
324
|
data_or_draw: DataObject | DrawFn,
|
|
301
|
-
maybe_strategy: MaybeSearchStrategy[
|
|
302
|
-
default: SearchStrategy[
|
|
325
|
+
maybe_strategy: MaybeSearchStrategy[T | None | Sentinel],
|
|
326
|
+
default: SearchStrategy[T | None],
|
|
303
327
|
/,
|
|
304
328
|
*,
|
|
305
329
|
sentinel: Literal[True],
|
|
306
|
-
) ->
|
|
330
|
+
) -> T | None: ...
|
|
307
331
|
@overload
|
|
308
|
-
def draw2(
|
|
332
|
+
def draw2[T](
|
|
309
333
|
data_or_draw: DataObject | DrawFn,
|
|
310
|
-
maybe_strategy: MaybeSearchStrategy[
|
|
311
|
-
default: SearchStrategy[
|
|
334
|
+
maybe_strategy: MaybeSearchStrategy[T | None],
|
|
335
|
+
default: SearchStrategy[T],
|
|
312
336
|
/,
|
|
313
337
|
*,
|
|
314
338
|
sentinel: Literal[False] = False,
|
|
315
|
-
) ->
|
|
339
|
+
) -> T: ...
|
|
316
340
|
@overload
|
|
317
|
-
def draw2(
|
|
341
|
+
def draw2[T](
|
|
318
342
|
data_or_draw: DataObject | DrawFn,
|
|
319
|
-
maybe_strategy: MaybeSearchStrategy[
|
|
320
|
-
default: SearchStrategy[
|
|
343
|
+
maybe_strategy: MaybeSearchStrategy[T | None | Sentinel],
|
|
344
|
+
default: SearchStrategy[T] | None = None,
|
|
321
345
|
/,
|
|
322
346
|
*,
|
|
323
347
|
sentinel: bool = False,
|
|
324
|
-
) ->
|
|
325
|
-
def draw2(
|
|
348
|
+
) -> T | None: ...
|
|
349
|
+
def draw2[T](
|
|
326
350
|
data_or_draw: DataObject | DrawFn,
|
|
327
|
-
maybe_strategy: MaybeSearchStrategy[
|
|
328
|
-
default: SearchStrategy[
|
|
351
|
+
maybe_strategy: MaybeSearchStrategy[T | None | Sentinel],
|
|
352
|
+
default: SearchStrategy[T | None] | None = None,
|
|
329
353
|
/,
|
|
330
354
|
*,
|
|
331
355
|
sentinel: bool = False,
|
|
332
|
-
) ->
|
|
356
|
+
) -> T | None:
|
|
333
357
|
"""Draw an element from a strategy, unless you require it to be non-nullable."""
|
|
334
358
|
draw = data_or_draw.draw if isinstance(data_or_draw, DataObject) else data_or_draw
|
|
335
359
|
if isinstance(maybe_strategy, SearchStrategy):
|
|
@@ -343,21 +367,21 @@ def draw2(
|
|
|
343
367
|
return value
|
|
344
368
|
case None, SearchStrategy(), False:
|
|
345
369
|
value2 = draw(default)
|
|
346
|
-
if
|
|
370
|
+
if is_sentinel(value2):
|
|
347
371
|
raise _Draw2DefaultGeneratedSentinelError
|
|
348
372
|
return value2
|
|
349
373
|
case Sentinel(), None, _:
|
|
350
374
|
raise _Draw2InputResolvedToSentinelError
|
|
351
375
|
case Sentinel(), SearchStrategy(), True:
|
|
352
376
|
value2 = draw(default)
|
|
353
|
-
if
|
|
377
|
+
if is_sentinel(value2):
|
|
354
378
|
raise _Draw2DefaultGeneratedSentinelError
|
|
355
379
|
return value2
|
|
356
380
|
case Sentinel(), SearchStrategy(), False:
|
|
357
381
|
raise _Draw2InputResolvedToSentinelError
|
|
358
382
|
case _, _, _:
|
|
359
383
|
return value
|
|
360
|
-
case
|
|
384
|
+
case never:
|
|
361
385
|
assert_never(never)
|
|
362
386
|
|
|
363
387
|
|
|
@@ -387,16 +411,27 @@ def float32s(
|
|
|
387
411
|
draw: DrawFn,
|
|
388
412
|
/,
|
|
389
413
|
*,
|
|
390
|
-
min_value: MaybeSearchStrategy[float] =
|
|
391
|
-
max_value: MaybeSearchStrategy[float] =
|
|
414
|
+
min_value: MaybeSearchStrategy[float | None] = None,
|
|
415
|
+
max_value: MaybeSearchStrategy[float | None] = None,
|
|
416
|
+
exclude_min: MaybeSearchStrategy[bool] = False,
|
|
417
|
+
exclude_max: MaybeSearchStrategy[bool] = False,
|
|
392
418
|
) -> float:
|
|
393
419
|
"""Strategy for generating float32s."""
|
|
394
420
|
min_value_, max_value_ = [draw2(draw, v) for v in [min_value, max_value]]
|
|
395
|
-
min_value_ =
|
|
396
|
-
max_value_ =
|
|
421
|
+
min_value_ = max_nullable([min_value_, MIN_FLOAT32])
|
|
422
|
+
max_value_ = min_nullable([max_value_, MAX_FLOAT32])
|
|
397
423
|
if is_zero(min_value_) and is_zero(max_value_):
|
|
398
424
|
min_value_ = max_value_ = 0.0
|
|
399
|
-
|
|
425
|
+
exclude_min_, exclude_max_ = [draw2(draw, e) for e in [exclude_min, exclude_max]]
|
|
426
|
+
return draw(
|
|
427
|
+
floats(
|
|
428
|
+
min_value_,
|
|
429
|
+
max_value_,
|
|
430
|
+
width=32,
|
|
431
|
+
exclude_min=exclude_min_,
|
|
432
|
+
exclude_max=exclude_max_,
|
|
433
|
+
)
|
|
434
|
+
)
|
|
400
435
|
|
|
401
436
|
|
|
402
437
|
@composite
|
|
@@ -404,16 +439,27 @@ def float64s(
|
|
|
404
439
|
draw: DrawFn,
|
|
405
440
|
/,
|
|
406
441
|
*,
|
|
407
|
-
min_value: MaybeSearchStrategy[float] =
|
|
408
|
-
max_value: MaybeSearchStrategy[float] =
|
|
442
|
+
min_value: MaybeSearchStrategy[float | None] = None,
|
|
443
|
+
max_value: MaybeSearchStrategy[float | None] = None,
|
|
444
|
+
exclude_min: MaybeSearchStrategy[bool] = False,
|
|
445
|
+
exclude_max: MaybeSearchStrategy[bool] = False,
|
|
409
446
|
) -> float:
|
|
410
447
|
"""Strategy for generating float64s."""
|
|
411
448
|
min_value_, max_value_ = [draw2(draw, v) for v in [min_value, max_value]]
|
|
412
|
-
min_value_ =
|
|
413
|
-
max_value_ =
|
|
449
|
+
min_value_ = max_nullable([min_value_, MIN_FLOAT64])
|
|
450
|
+
max_value_ = min_nullable([max_value_, MAX_FLOAT64])
|
|
414
451
|
if is_zero(min_value_) and is_zero(max_value_):
|
|
415
452
|
min_value_ = max_value_ = 0.0
|
|
416
|
-
|
|
453
|
+
exclude_min_, exclude_max_ = [draw2(draw, e) for e in [exclude_min, exclude_max]]
|
|
454
|
+
return draw(
|
|
455
|
+
floats(
|
|
456
|
+
min_value_,
|
|
457
|
+
max_value_,
|
|
458
|
+
width=64,
|
|
459
|
+
exclude_min=exclude_min_,
|
|
460
|
+
exclude_max=exclude_max_,
|
|
461
|
+
)
|
|
462
|
+
)
|
|
417
463
|
|
|
418
464
|
|
|
419
465
|
##
|
|
@@ -533,6 +579,59 @@ def hashables() -> SearchStrategy[Hashable]:
|
|
|
533
579
|
##
|
|
534
580
|
|
|
535
581
|
|
|
582
|
+
@composite
|
|
583
|
+
def import_froms(
|
|
584
|
+
draw: DrawFn,
|
|
585
|
+
/,
|
|
586
|
+
*,
|
|
587
|
+
min_depth: MaybeSearchStrategy[int | None] = None,
|
|
588
|
+
max_depth: MaybeSearchStrategy[int | None] = None,
|
|
589
|
+
) -> ImportFrom:
|
|
590
|
+
"""Strategy for generating import-froms."""
|
|
591
|
+
from utilities.libcst import generate_import_from
|
|
592
|
+
|
|
593
|
+
min_depth_, max_depth_ = [draw2(draw, d) for d in [min_depth, max_depth]]
|
|
594
|
+
path = draw(
|
|
595
|
+
paths(
|
|
596
|
+
min_depth=1 if min_depth_ is None else max(min_depth_, 1),
|
|
597
|
+
max_depth=max_depth_,
|
|
598
|
+
)
|
|
599
|
+
)
|
|
600
|
+
module = module_path(path)
|
|
601
|
+
name = draw(text_ascii(min_size=1))
|
|
602
|
+
asname = draw(text_ascii(min_size=1) | none())
|
|
603
|
+
return generate_import_from(module, name, asname=asname)
|
|
604
|
+
|
|
605
|
+
|
|
606
|
+
##
|
|
607
|
+
|
|
608
|
+
|
|
609
|
+
@composite
|
|
610
|
+
def imports(
|
|
611
|
+
draw: DrawFn,
|
|
612
|
+
/,
|
|
613
|
+
*,
|
|
614
|
+
min_depth: MaybeSearchStrategy[int | None] = None,
|
|
615
|
+
max_depth: MaybeSearchStrategy[int | None] = None,
|
|
616
|
+
) -> Import:
|
|
617
|
+
"""Strategy for generating imports."""
|
|
618
|
+
from utilities.libcst import generate_import
|
|
619
|
+
|
|
620
|
+
min_depth_, max_depth_ = [draw2(draw, d) for d in [min_depth, max_depth]]
|
|
621
|
+
path = draw(
|
|
622
|
+
paths(
|
|
623
|
+
min_depth=1 if min_depth_ is None else max(min_depth_, 1),
|
|
624
|
+
max_depth=max_depth_,
|
|
625
|
+
)
|
|
626
|
+
)
|
|
627
|
+
module = module_path(path)
|
|
628
|
+
asname = draw(text_ascii(min_size=1) | none())
|
|
629
|
+
return generate_import(module, asname=asname)
|
|
630
|
+
|
|
631
|
+
|
|
632
|
+
##
|
|
633
|
+
|
|
634
|
+
|
|
536
635
|
@composite
|
|
537
636
|
def int_arrays(
|
|
538
637
|
draw: DrawFn,
|
|
@@ -562,18 +661,48 @@ def int_arrays(
|
|
|
562
661
|
##
|
|
563
662
|
|
|
564
663
|
|
|
664
|
+
@composite
|
|
665
|
+
def int8s(
|
|
666
|
+
draw: DrawFn,
|
|
667
|
+
/,
|
|
668
|
+
*,
|
|
669
|
+
min_value: MaybeSearchStrategy[int | None] = None,
|
|
670
|
+
max_value: MaybeSearchStrategy[int | None] = None,
|
|
671
|
+
) -> int:
|
|
672
|
+
"""Strategy for generating int8s."""
|
|
673
|
+
min_value_, max_value_ = [draw2(draw, v) for v in [min_value, max_value]]
|
|
674
|
+
min_value_ = max_nullable([min_value_, MIN_INT8])
|
|
675
|
+
max_value_ = min_nullable([max_value_, MAX_INT8])
|
|
676
|
+
return draw(integers(min_value=min_value_, max_value=max_value_))
|
|
677
|
+
|
|
678
|
+
|
|
679
|
+
@composite
|
|
680
|
+
def int16s(
|
|
681
|
+
draw: DrawFn,
|
|
682
|
+
/,
|
|
683
|
+
*,
|
|
684
|
+
min_value: MaybeSearchStrategy[int | None] = None,
|
|
685
|
+
max_value: MaybeSearchStrategy[int | None] = None,
|
|
686
|
+
) -> int:
|
|
687
|
+
"""Strategy for generating int16s."""
|
|
688
|
+
min_value_, max_value_ = [draw2(draw, v) for v in [min_value, max_value]]
|
|
689
|
+
min_value_ = max_nullable([min_value_, MIN_INT16])
|
|
690
|
+
max_value_ = min_nullable([max_value_, MAX_INT16])
|
|
691
|
+
return draw(integers(min_value=min_value_, max_value=max_value_))
|
|
692
|
+
|
|
693
|
+
|
|
565
694
|
@composite
|
|
566
695
|
def int32s(
|
|
567
696
|
draw: DrawFn,
|
|
568
697
|
/,
|
|
569
698
|
*,
|
|
570
|
-
min_value: MaybeSearchStrategy[int] =
|
|
571
|
-
max_value: MaybeSearchStrategy[int] =
|
|
699
|
+
min_value: MaybeSearchStrategy[int | None] = None,
|
|
700
|
+
max_value: MaybeSearchStrategy[int | None] = None,
|
|
572
701
|
) -> int:
|
|
573
702
|
"""Strategy for generating int32s."""
|
|
574
703
|
min_value_, max_value_ = [draw2(draw, v) for v in [min_value, max_value]]
|
|
575
|
-
min_value_ =
|
|
576
|
-
max_value_ =
|
|
704
|
+
min_value_ = max_nullable([min_value_, MIN_INT32])
|
|
705
|
+
max_value_ = min_nullable([max_value_, MAX_INT32])
|
|
577
706
|
return draw(integers(min_value_, max_value_))
|
|
578
707
|
|
|
579
708
|
|
|
@@ -582,13 +711,13 @@ def int64s(
|
|
|
582
711
|
draw: DrawFn,
|
|
583
712
|
/,
|
|
584
713
|
*,
|
|
585
|
-
min_value: MaybeSearchStrategy[int] =
|
|
586
|
-
max_value: MaybeSearchStrategy[int] =
|
|
714
|
+
min_value: MaybeSearchStrategy[int | None] = None,
|
|
715
|
+
max_value: MaybeSearchStrategy[int | None] = None,
|
|
587
716
|
) -> int:
|
|
588
717
|
"""Strategy for generating int64s."""
|
|
589
718
|
min_value_, max_value_ = [draw2(draw, v) for v in [min_value, max_value]]
|
|
590
|
-
min_value_ =
|
|
591
|
-
max_value_ =
|
|
719
|
+
min_value_ = max_nullable([min_value_, MIN_INT64])
|
|
720
|
+
max_value_ = min_nullable([max_value_, MAX_INT64])
|
|
592
721
|
return draw(integers(min_value_, max_value_))
|
|
593
722
|
|
|
594
723
|
|
|
@@ -596,15 +725,15 @@ def int64s(
|
|
|
596
725
|
|
|
597
726
|
|
|
598
727
|
@composite
|
|
599
|
-
def lists_fixed_length(
|
|
728
|
+
def lists_fixed_length[T](
|
|
600
729
|
draw: DrawFn,
|
|
601
|
-
strategy: SearchStrategy[
|
|
730
|
+
strategy: SearchStrategy[T],
|
|
602
731
|
size: MaybeSearchStrategy[int],
|
|
603
732
|
/,
|
|
604
733
|
*,
|
|
605
734
|
unique: MaybeSearchStrategy[bool] = False,
|
|
606
735
|
sorted: MaybeSearchStrategy[bool] = False, # noqa: A002
|
|
607
|
-
) -> list[
|
|
736
|
+
) -> list[T]:
|
|
608
737
|
"""Strategy for generating lists of a fixed length."""
|
|
609
738
|
size_ = draw2(draw, size)
|
|
610
739
|
elements = draw(
|
|
@@ -619,243 +748,32 @@ def lists_fixed_length(
|
|
|
619
748
|
|
|
620
749
|
|
|
621
750
|
@composite
|
|
622
|
-
def
|
|
623
|
-
draw: DrawFn,
|
|
624
|
-
/,
|
|
625
|
-
*,
|
|
626
|
-
min_value: MaybeSearchStrategy[dt.datetime | None] = None,
|
|
627
|
-
max_value: MaybeSearchStrategy[dt.datetime | None] = None,
|
|
628
|
-
time_zone: MaybeSearchStrategy[ZoneInfo | timezone] = UTC,
|
|
629
|
-
round_: RoundMode | None = None,
|
|
630
|
-
timedelta: dt.timedelta | None = None,
|
|
631
|
-
rel_tol: float | None = None,
|
|
632
|
-
abs_tol: float | None = None,
|
|
633
|
-
valid: bool = False,
|
|
634
|
-
) -> tuple[dt.datetime, dt.datetime]:
|
|
635
|
-
"""Strategy for generating min/max datetimes."""
|
|
636
|
-
match min_value, max_value:
|
|
637
|
-
case None, None:
|
|
638
|
-
return draw(
|
|
639
|
-
pairs(
|
|
640
|
-
zoned_datetimes(
|
|
641
|
-
time_zone=time_zone,
|
|
642
|
-
round_=round_,
|
|
643
|
-
timedelta=timedelta,
|
|
644
|
-
rel_tol=rel_tol,
|
|
645
|
-
abs_tol=abs_tol,
|
|
646
|
-
valid=valid,
|
|
647
|
-
),
|
|
648
|
-
sorted=True,
|
|
649
|
-
)
|
|
650
|
-
)
|
|
651
|
-
case None, dt.datetime():
|
|
652
|
-
min_value_ = draw(
|
|
653
|
-
zoned_datetimes(
|
|
654
|
-
max_value=max_value,
|
|
655
|
-
time_zone=time_zone,
|
|
656
|
-
round_=round_,
|
|
657
|
-
timedelta=timedelta,
|
|
658
|
-
rel_tol=rel_tol,
|
|
659
|
-
abs_tol=abs_tol,
|
|
660
|
-
valid=valid,
|
|
661
|
-
)
|
|
662
|
-
)
|
|
663
|
-
return min_value_, max_value
|
|
664
|
-
case dt.datetime(), None:
|
|
665
|
-
max_value_ = draw(
|
|
666
|
-
zoned_datetimes(
|
|
667
|
-
min_value=min_value,
|
|
668
|
-
time_zone=time_zone,
|
|
669
|
-
round_=round_,
|
|
670
|
-
timedelta=timedelta,
|
|
671
|
-
rel_tol=rel_tol,
|
|
672
|
-
abs_tol=abs_tol,
|
|
673
|
-
valid=valid,
|
|
674
|
-
)
|
|
675
|
-
)
|
|
676
|
-
return min_value, max_value_
|
|
677
|
-
case dt.datetime(), dt.datetime():
|
|
678
|
-
_ = assume(min_value <= max_value)
|
|
679
|
-
return min_value, max_value
|
|
680
|
-
case _, _:
|
|
681
|
-
strategy = zoned_datetimes(
|
|
682
|
-
time_zone=time_zone,
|
|
683
|
-
round_=round_,
|
|
684
|
-
timedelta=timedelta,
|
|
685
|
-
rel_tol=rel_tol,
|
|
686
|
-
abs_tol=abs_tol,
|
|
687
|
-
valid=valid,
|
|
688
|
-
)
|
|
689
|
-
min_value_ = draw2(draw, min_value, strategy)
|
|
690
|
-
max_value_ = draw2(draw, max_value, strategy)
|
|
691
|
-
_ = assume(min_value_ <= max_value_)
|
|
692
|
-
return min_value_, max_value_
|
|
693
|
-
case _ as never:
|
|
694
|
-
assert_never(never)
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
##
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
@composite
|
|
701
|
-
def min_and_maybe_max_datetimes(
|
|
751
|
+
def month_days(
|
|
702
752
|
draw: DrawFn,
|
|
703
753
|
/,
|
|
704
754
|
*,
|
|
705
|
-
min_value: MaybeSearchStrategy[
|
|
706
|
-
max_value: MaybeSearchStrategy[
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
)
|
|
714
|
-
|
|
715
|
-
case
|
|
716
|
-
min_value_, max_value_ = draw(
|
|
717
|
-
pairs(
|
|
718
|
-
zoned_datetimes(
|
|
719
|
-
time_zone=time_zone,
|
|
720
|
-
round_=round_,
|
|
721
|
-
timedelta=timedelta,
|
|
722
|
-
rel_tol=rel_tol,
|
|
723
|
-
abs_tol=abs_tol,
|
|
724
|
-
valid=valid,
|
|
725
|
-
),
|
|
726
|
-
sorted=True,
|
|
727
|
-
)
|
|
728
|
-
)
|
|
729
|
-
return min_value_, draw(just(max_value_) | none())
|
|
730
|
-
case None, None:
|
|
731
|
-
min_value_ = draw(
|
|
732
|
-
zoned_datetimes(
|
|
733
|
-
time_zone=time_zone,
|
|
734
|
-
round_=round_,
|
|
735
|
-
timedelta=timedelta,
|
|
736
|
-
rel_tol=rel_tol,
|
|
737
|
-
abs_tol=abs_tol,
|
|
738
|
-
valid=valid,
|
|
739
|
-
)
|
|
740
|
-
)
|
|
741
|
-
return min_value_, None
|
|
742
|
-
case None, dt.datetime():
|
|
743
|
-
min_value_ = draw(
|
|
744
|
-
zoned_datetimes(
|
|
745
|
-
max_value=max_value,
|
|
746
|
-
time_zone=time_zone,
|
|
747
|
-
round_=round_,
|
|
748
|
-
timedelta=timedelta,
|
|
749
|
-
rel_tol=rel_tol,
|
|
750
|
-
abs_tol=abs_tol,
|
|
751
|
-
valid=valid,
|
|
752
|
-
)
|
|
753
|
-
)
|
|
754
|
-
return min_value_, max_value
|
|
755
|
-
case dt.datetime(), Sentinel():
|
|
756
|
-
max_value_ = draw(
|
|
757
|
-
zoned_datetimes(
|
|
758
|
-
min_value=min_value,
|
|
759
|
-
time_zone=time_zone,
|
|
760
|
-
round_=round_,
|
|
761
|
-
timedelta=timedelta,
|
|
762
|
-
rel_tol=rel_tol,
|
|
763
|
-
abs_tol=abs_tol,
|
|
764
|
-
valid=valid,
|
|
765
|
-
)
|
|
766
|
-
| none()
|
|
767
|
-
)
|
|
768
|
-
return min_value, max_value_
|
|
769
|
-
case dt.datetime(), None:
|
|
770
|
-
return min_value, None
|
|
771
|
-
case dt.datetime(), dt.datetime():
|
|
772
|
-
_ = assume(min_value <= max_value)
|
|
773
|
-
return min_value, max_value
|
|
774
|
-
case _, _:
|
|
775
|
-
strategy = zoned_datetimes(
|
|
776
|
-
time_zone=time_zone,
|
|
777
|
-
round_=round_,
|
|
778
|
-
timedelta=timedelta,
|
|
779
|
-
rel_tol=rel_tol,
|
|
780
|
-
abs_tol=abs_tol,
|
|
781
|
-
valid=valid,
|
|
782
|
-
)
|
|
783
|
-
min_value_ = draw2(draw, min_value, strategy)
|
|
784
|
-
max_value_ = draw2(draw, max_value, strategy | none(), sentinel=True)
|
|
785
|
-
_ = assume((max_value_ is None) or (min_value_ <= max_value_))
|
|
786
|
-
return min_value_, max_value_
|
|
787
|
-
case _ as never:
|
|
755
|
+
min_value: MaybeSearchStrategy[MonthDay | None] = None,
|
|
756
|
+
max_value: MaybeSearchStrategy[MonthDay | None] = None,
|
|
757
|
+
) -> MonthDay:
|
|
758
|
+
"""Strategy for generating month-days."""
|
|
759
|
+
min_value_, max_value_ = [draw2(draw, v) for v in [min_value, max_value]]
|
|
760
|
+
match min_value_:
|
|
761
|
+
case None:
|
|
762
|
+
min_value_ = MonthDay.MIN
|
|
763
|
+
case MonthDay():
|
|
764
|
+
...
|
|
765
|
+
case never:
|
|
788
766
|
assert_never(never)
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
def min_and_maybe_max_sizes(
|
|
796
|
-
draw: DrawFn,
|
|
797
|
-
/,
|
|
798
|
-
*,
|
|
799
|
-
min_value: MaybeSearchStrategy[int | None] = None,
|
|
800
|
-
max_value: MaybeSearchStrategy[int | None | Sentinel] = sentinel,
|
|
801
|
-
) -> tuple[int, int | None]:
|
|
802
|
-
match min_value, max_value:
|
|
803
|
-
case None, Sentinel():
|
|
804
|
-
min_value_, max_value_ = draw(pairs(integers(min_value=0), sorted=True))
|
|
805
|
-
return min_value_, draw(just(max_value_) | none())
|
|
806
|
-
case None, None:
|
|
807
|
-
min_value_ = draw(integers(min_value=0))
|
|
808
|
-
return min_value_, None
|
|
809
|
-
case None, int():
|
|
810
|
-
min_value_ = draw(integers(0, max_value))
|
|
811
|
-
return min_value_, max_value
|
|
812
|
-
case int(), Sentinel():
|
|
813
|
-
max_value_ = draw(integers(min_value=min_value) | none())
|
|
814
|
-
return min_value, max_value_
|
|
815
|
-
case int(), None:
|
|
816
|
-
return min_value, None
|
|
817
|
-
case int(), int():
|
|
818
|
-
_ = assume(min_value <= max_value)
|
|
819
|
-
return min_value, max_value
|
|
820
|
-
case _, _:
|
|
821
|
-
strategy = integers(min_value=0)
|
|
822
|
-
min_value_ = draw2(draw, min_value, strategy)
|
|
823
|
-
max_value_ = draw2(draw, max_value, strategy | none(), sentinel=True)
|
|
824
|
-
_ = assume((max_value_ is None) or (min_value_ <= max_value_))
|
|
825
|
-
return min_value_, max_value_
|
|
826
|
-
case _ as never:
|
|
767
|
+
match max_value_:
|
|
768
|
+
case None:
|
|
769
|
+
max_value_ = MonthDay.MAX
|
|
770
|
+
case MonthDay():
|
|
771
|
+
...
|
|
772
|
+
case never:
|
|
827
773
|
assert_never(never)
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
@composite
|
|
834
|
-
def months(
|
|
835
|
-
draw: DrawFn,
|
|
836
|
-
/,
|
|
837
|
-
*,
|
|
838
|
-
min_value: MaybeSearchStrategy[Month] = MIN_MONTH,
|
|
839
|
-
max_value: MaybeSearchStrategy[Month] = MAX_MONTH,
|
|
840
|
-
) -> Month:
|
|
841
|
-
"""Strategy for generating datetimes with the UTC timezone."""
|
|
842
|
-
min_value_, max_value_ = [draw2(draw, v).to_date() for v in [min_value, max_value]]
|
|
843
|
-
date = draw(dates(min_value=min_value_, max_value=max_value_))
|
|
844
|
-
return date_to_month(date)
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
##
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
@composite
|
|
851
|
-
def namespace_mixins(draw: DrawFn, /) -> type:
|
|
852
|
-
"""Strategy for generating task namespace mixins."""
|
|
853
|
-
path = draw(temp_paths())
|
|
854
|
-
|
|
855
|
-
class NamespaceMixin:
|
|
856
|
-
task_namespace = path.name
|
|
857
|
-
|
|
858
|
-
return NamespaceMixin
|
|
774
|
+
min_date, max_date = [m.in_year(2000) for m in [min_value_, max_value_]]
|
|
775
|
+
date = draw(dates(min_value=min_date, max_value=max_date))
|
|
776
|
+
return date.month_day()
|
|
859
777
|
|
|
860
778
|
|
|
861
779
|
##
|
|
@@ -901,18 +819,18 @@ def numbers(
|
|
|
901
819
|
##
|
|
902
820
|
|
|
903
821
|
|
|
904
|
-
def pairs(
|
|
905
|
-
strategy: SearchStrategy[
|
|
822
|
+
def pairs[T](
|
|
823
|
+
strategy: SearchStrategy[T],
|
|
906
824
|
/,
|
|
907
825
|
*,
|
|
908
826
|
unique: MaybeSearchStrategy[bool] = False,
|
|
909
827
|
sorted: MaybeSearchStrategy[bool] = False, # noqa: A002
|
|
910
|
-
) -> SearchStrategy[tuple[
|
|
828
|
+
) -> SearchStrategy[tuple[T, T]]:
|
|
911
829
|
"""Strategy for generating pairs of elements."""
|
|
912
830
|
return lists_fixed_length(strategy, 2, unique=unique, sorted=sorted).map(_pairs_map)
|
|
913
831
|
|
|
914
832
|
|
|
915
|
-
def _pairs_map(elements: list[
|
|
833
|
+
def _pairs_map[T](elements: list[T], /) -> tuple[T, T]:
|
|
916
834
|
first, second = elements
|
|
917
835
|
return first, second
|
|
918
836
|
|
|
@@ -920,48 +838,135 @@ def _pairs_map(elements: list[_T], /) -> tuple[_T, _T]:
|
|
|
920
838
|
##
|
|
921
839
|
|
|
922
840
|
|
|
923
|
-
|
|
841
|
+
@composite
|
|
842
|
+
def paths(
|
|
843
|
+
draw: DrawFn,
|
|
844
|
+
/,
|
|
845
|
+
*,
|
|
846
|
+
min_depth: MaybeSearchStrategy[int | None] = None,
|
|
847
|
+
max_depth: MaybeSearchStrategy[int | None] = None,
|
|
848
|
+
) -> Path:
|
|
924
849
|
"""Strategy for generating `Path`s."""
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
850
|
+
min_depth_, max_depth_ = [draw2(draw, d) for d in [min_depth, max_depth]]
|
|
851
|
+
min_depth_ = max_nullable([min_depth_, 0])
|
|
852
|
+
max_depth_ = min_nullable([max_depth_, 10])
|
|
853
|
+
parts = draw(lists(_path_parts(), min_size=min_depth_, max_size=max_depth_))
|
|
854
|
+
return Path(*parts)
|
|
855
|
+
|
|
856
|
+
|
|
857
|
+
@composite
|
|
858
|
+
def _path_parts(draw: DrawFn, /) -> str:
|
|
859
|
+
part = draw(text_ascii(min_size=1, max_size=10))
|
|
860
|
+
reserved = {"AUX", "NUL", "nuL", "pRn"}
|
|
861
|
+
_ = assume(part not in reserved)
|
|
862
|
+
return part
|
|
928
863
|
|
|
929
864
|
|
|
930
865
|
##
|
|
931
866
|
|
|
932
867
|
|
|
933
868
|
@composite
|
|
934
|
-
def
|
|
869
|
+
def permissions(
|
|
935
870
|
draw: DrawFn,
|
|
936
871
|
/,
|
|
937
872
|
*,
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
873
|
+
user_read: MaybeSearchStrategy[bool | None] = None,
|
|
874
|
+
user_write: MaybeSearchStrategy[bool | None] = None,
|
|
875
|
+
user_execute: MaybeSearchStrategy[bool | None] = None,
|
|
876
|
+
group_read: MaybeSearchStrategy[bool | None] = None,
|
|
877
|
+
group_write: MaybeSearchStrategy[bool | None] = None,
|
|
878
|
+
group_execute: MaybeSearchStrategy[bool | None] = None,
|
|
879
|
+
others_read: MaybeSearchStrategy[bool | None] = None,
|
|
880
|
+
others_write: MaybeSearchStrategy[bool | None] = None,
|
|
881
|
+
others_execute: MaybeSearchStrategy[bool | None] = None,
|
|
882
|
+
) -> Permissions:
|
|
883
|
+
"""Strategy for generating `Permissions`."""
|
|
884
|
+
return Permissions(
|
|
885
|
+
user_read=draw2(draw, user_read, booleans()),
|
|
886
|
+
user_write=draw2(draw, user_write, booleans()),
|
|
887
|
+
user_execute=draw2(draw, user_execute, booleans()),
|
|
888
|
+
group_read=draw2(draw, group_read, booleans()),
|
|
889
|
+
group_write=draw2(draw, group_write, booleans()),
|
|
890
|
+
group_execute=draw2(draw, group_execute, booleans()),
|
|
891
|
+
others_read=draw2(draw, others_read, booleans()),
|
|
892
|
+
others_write=draw2(draw, others_write, booleans()),
|
|
893
|
+
others_execute=draw2(draw, others_execute, booleans()),
|
|
894
|
+
)
|
|
895
|
+
|
|
896
|
+
|
|
897
|
+
##
|
|
898
|
+
|
|
899
|
+
|
|
900
|
+
@composite
|
|
901
|
+
def plain_date_times(
|
|
902
|
+
draw: DrawFn,
|
|
903
|
+
/,
|
|
904
|
+
*,
|
|
905
|
+
min_value: MaybeSearchStrategy[PlainDateTime | None] = None,
|
|
906
|
+
max_value: MaybeSearchStrategy[PlainDateTime | None] = None,
|
|
907
|
+
) -> PlainDateTime:
|
|
945
908
|
"""Strategy for generating plain datetimes."""
|
|
946
909
|
min_value_, max_value_ = [draw2(draw, v) for v in [min_value, max_value]]
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
910
|
+
match min_value_:
|
|
911
|
+
case None:
|
|
912
|
+
min_value_ = PlainDateTime.MIN
|
|
913
|
+
case PlainDateTime():
|
|
914
|
+
...
|
|
915
|
+
case never:
|
|
916
|
+
assert_never(never)
|
|
917
|
+
match max_value_:
|
|
918
|
+
case None:
|
|
919
|
+
max_value_ = PlainDateTime.MAX
|
|
920
|
+
case PlainDateTime():
|
|
921
|
+
...
|
|
922
|
+
case never:
|
|
923
|
+
assert_never(never)
|
|
924
|
+
py_datetime = draw(
|
|
925
|
+
datetimes(
|
|
926
|
+
min_value=min_value_.py_datetime(), max_value=max_value_.py_datetime()
|
|
953
927
|
)
|
|
954
|
-
|
|
955
|
-
return
|
|
928
|
+
)
|
|
929
|
+
return PlainDateTime.from_py_datetime(py_datetime)
|
|
956
930
|
|
|
957
931
|
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
932
|
+
##
|
|
933
|
+
|
|
934
|
+
|
|
935
|
+
@composite
|
|
936
|
+
def py_datetimes(
|
|
937
|
+
draw: DrawFn, /, *, zoned: MaybeSearchStrategy[bool | None] = None
|
|
938
|
+
) -> dt.datetime:
|
|
939
|
+
"""Strategy for generating standard library datetimes."""
|
|
940
|
+
zoned_ = draw2(draw, zoned, booleans())
|
|
941
|
+
timezones = just(UTC) if zoned_ else none()
|
|
942
|
+
return draw(
|
|
943
|
+
hypothesis.strategies.datetimes(
|
|
944
|
+
min_value=dt.datetime(2000, 1, 1), # noqa: DTZ001
|
|
945
|
+
max_value=dt.datetime(2000, 12, 31), # noqa: DTZ001
|
|
946
|
+
timezones=timezones,
|
|
947
|
+
)
|
|
948
|
+
)
|
|
961
949
|
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
950
|
+
|
|
951
|
+
##
|
|
952
|
+
|
|
953
|
+
|
|
954
|
+
def quadruples[T](
|
|
955
|
+
strategy: SearchStrategy[T],
|
|
956
|
+
/,
|
|
957
|
+
*,
|
|
958
|
+
unique: MaybeSearchStrategy[bool] = False,
|
|
959
|
+
sorted: MaybeSearchStrategy[bool] = False, # noqa: A002
|
|
960
|
+
) -> SearchStrategy[tuple[T, T, T, T]]:
|
|
961
|
+
"""Strategy for generating quadruples of elements."""
|
|
962
|
+
return lists_fixed_length(strategy, 4, unique=unique, sorted=sorted).map(
|
|
963
|
+
_quadruples_map
|
|
964
|
+
)
|
|
965
|
+
|
|
966
|
+
|
|
967
|
+
def _quadruples_map[T](elements: list[T], /) -> tuple[T, T, T, T]:
|
|
968
|
+
first, second, third, fourth = elements
|
|
969
|
+
return first, second, third, fourth
|
|
965
970
|
|
|
966
971
|
|
|
967
972
|
##
|
|
@@ -974,7 +979,7 @@ def random_states(
|
|
|
974
979
|
"""Strategy for generating `numpy` random states."""
|
|
975
980
|
from numpy.random import RandomState
|
|
976
981
|
|
|
977
|
-
seed_ = draw2(draw, seed,
|
|
982
|
+
seed_ = draw2(draw, seed, uint32s())
|
|
978
983
|
return RandomState(seed=seed_)
|
|
979
984
|
|
|
980
985
|
|
|
@@ -990,9 +995,9 @@ def sentinels() -> SearchStrategy[Sentinel]:
|
|
|
990
995
|
|
|
991
996
|
|
|
992
997
|
@composite
|
|
993
|
-
def sets_fixed_length(
|
|
994
|
-
draw: DrawFn, strategy: SearchStrategy[
|
|
995
|
-
) -> set[
|
|
998
|
+
def sets_fixed_length[T](
|
|
999
|
+
draw: DrawFn, strategy: SearchStrategy[T], size: MaybeSearchStrategy[int], /
|
|
1000
|
+
) -> set[T]:
|
|
996
1001
|
"""Strategy for generating lists of a fixed length."""
|
|
997
1002
|
size_ = draw2(draw, size)
|
|
998
1003
|
return draw(sets(strategy, min_size=size_, max_size=size_))
|
|
@@ -1021,7 +1026,7 @@ def setup_hypothesis_profiles(
|
|
|
1021
1026
|
return 100
|
|
1022
1027
|
case Profile.ci:
|
|
1023
1028
|
return 1000
|
|
1024
|
-
case
|
|
1029
|
+
case never:
|
|
1025
1030
|
assert_never(never)
|
|
1026
1031
|
|
|
1027
1032
|
@property
|
|
@@ -1031,11 +1036,11 @@ def setup_hypothesis_profiles(
|
|
|
1031
1036
|
return Verbosity.quiet
|
|
1032
1037
|
case Profile.ci:
|
|
1033
1038
|
return Verbosity.verbose
|
|
1034
|
-
case
|
|
1039
|
+
case never:
|
|
1035
1040
|
assert_never(never)
|
|
1036
1041
|
|
|
1037
1042
|
phases = {Phase.explicit, Phase.reuse, Phase.generate, Phase.target}
|
|
1038
|
-
if "HYPOTHESIS_NO_SHRINK" not in environ:
|
|
1043
|
+
if "HYPOTHESIS_NO_SHRINK" not in environ: # pragma: no cover
|
|
1039
1044
|
phases.add(Phase.shrink)
|
|
1040
1045
|
for profile in Profile:
|
|
1041
1046
|
try:
|
|
@@ -1117,51 +1122,6 @@ def slices(
|
|
|
1117
1122
|
##
|
|
1118
1123
|
|
|
1119
1124
|
|
|
1120
|
-
_STRATEGY_DIALECTS: list[Dialect] = ["sqlite", "postgresql"]
|
|
1121
|
-
_SQLALCHEMY_ENGINE_DIALECTS = sampled_from(_STRATEGY_DIALECTS)
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
async def sqlalchemy_engines(
|
|
1125
|
-
data: DataObject,
|
|
1126
|
-
/,
|
|
1127
|
-
*tables_or_orms: TableOrORMInstOrClass,
|
|
1128
|
-
dialect: MaybeSearchStrategy[Dialect] = _SQLALCHEMY_ENGINE_DIALECTS,
|
|
1129
|
-
) -> AsyncEngine:
|
|
1130
|
-
"""Strategy for generating sqlalchemy engines."""
|
|
1131
|
-
from utilities.sqlalchemy import create_async_engine
|
|
1132
|
-
|
|
1133
|
-
dialect_: Dialect = draw2(data, dialect)
|
|
1134
|
-
if "CI" in environ: # pragma: no cover
|
|
1135
|
-
_ = assume(dialect_ == "sqlite")
|
|
1136
|
-
match dialect_:
|
|
1137
|
-
case "sqlite":
|
|
1138
|
-
temp_path = data.draw(temp_paths())
|
|
1139
|
-
path = Path(temp_path, "db.sqlite")
|
|
1140
|
-
engine = create_async_engine("sqlite+aiosqlite", database=str(path))
|
|
1141
|
-
|
|
1142
|
-
class EngineWithPath(type(engine)): ...
|
|
1143
|
-
|
|
1144
|
-
engine_with_path = EngineWithPath(engine.sync_engine)
|
|
1145
|
-
cast(
|
|
1146
|
-
"Any", engine_with_path
|
|
1147
|
-
).temp_path = temp_path # keep `temp_path` alive
|
|
1148
|
-
return engine_with_path
|
|
1149
|
-
case "postgresql": # skipif-ci-and-not-linux
|
|
1150
|
-
from utilities.sqlalchemy import ensure_tables_dropped
|
|
1151
|
-
|
|
1152
|
-
engine = create_async_engine(
|
|
1153
|
-
"postgresql+asyncpg", host="localhost", port=5432, database="testing"
|
|
1154
|
-
)
|
|
1155
|
-
with assume_does_not_raise(ConnectionRefusedError):
|
|
1156
|
-
await ensure_tables_dropped(engine, *tables_or_orms)
|
|
1157
|
-
return engine
|
|
1158
|
-
case _: # pragma: no cover
|
|
1159
|
-
raise NotImplementedError(dialect)
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
##
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
1125
|
@composite
|
|
1166
1126
|
def str_arrays(
|
|
1167
1127
|
draw: DrawFn,
|
|
@@ -1201,9 +1161,7 @@ def temp_dirs(draw: DrawFn, /) -> TemporaryDirectory:
|
|
|
1201
1161
|
"""Search strategy for temporary directories."""
|
|
1202
1162
|
_TEMP_DIR_HYPOTHESIS.mkdir(exist_ok=True)
|
|
1203
1163
|
uuid = draw(uuids())
|
|
1204
|
-
return TemporaryDirectory(
|
|
1205
|
-
prefix=f"{uuid}__", dir=_TEMP_DIR_HYPOTHESIS, ignore_cleanup_errors=IS_WINDOWS
|
|
1206
|
-
)
|
|
1164
|
+
return TemporaryDirectory(prefix=f"{uuid}__", dir=_TEMP_DIR_HYPOTHESIS)
|
|
1207
1165
|
|
|
1208
1166
|
|
|
1209
1167
|
##
|
|
@@ -1319,45 +1277,107 @@ def text_printable(
|
|
|
1319
1277
|
|
|
1320
1278
|
|
|
1321
1279
|
@composite
|
|
1322
|
-
def
|
|
1280
|
+
def time_deltas(
|
|
1323
1281
|
draw: DrawFn,
|
|
1324
1282
|
/,
|
|
1325
1283
|
*,
|
|
1326
|
-
min_value: MaybeSearchStrategy[
|
|
1327
|
-
max_value: MaybeSearchStrategy[
|
|
1328
|
-
) ->
|
|
1329
|
-
"""Strategy for generating
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1284
|
+
min_value: MaybeSearchStrategy[TimeDelta | None] = None,
|
|
1285
|
+
max_value: MaybeSearchStrategy[TimeDelta | None] = None,
|
|
1286
|
+
) -> TimeDelta:
|
|
1287
|
+
"""Strategy for generating time deltas."""
|
|
1288
|
+
min_value_, max_value_ = [draw2(draw, v) for v in [min_value, max_value]]
|
|
1289
|
+
match min_value_:
|
|
1290
|
+
case None:
|
|
1291
|
+
min_value_ = TIME_DELTA_MIN
|
|
1292
|
+
case TimeDelta():
|
|
1293
|
+
...
|
|
1294
|
+
case never:
|
|
1295
|
+
assert_never(never)
|
|
1296
|
+
match max_value_:
|
|
1297
|
+
case None:
|
|
1298
|
+
max_value_ = TIME_DELTA_MAX
|
|
1299
|
+
case TimeDelta():
|
|
1300
|
+
...
|
|
1301
|
+
case never:
|
|
1302
|
+
assert_never(never)
|
|
1303
|
+
py_time = draw(
|
|
1304
|
+
hypothesis.strategies.timedeltas(
|
|
1305
|
+
min_value=min_value_.py_timedelta(), max_value=max_value_.py_timedelta()
|
|
1306
|
+
)
|
|
1333
1307
|
)
|
|
1308
|
+
return TimeDelta.from_py_timedelta(py_time)
|
|
1334
1309
|
|
|
1310
|
+
|
|
1311
|
+
##
|
|
1312
|
+
|
|
1313
|
+
|
|
1314
|
+
@composite
|
|
1315
|
+
def time_periods(
|
|
1316
|
+
draw: DrawFn,
|
|
1317
|
+
/,
|
|
1318
|
+
*,
|
|
1319
|
+
min_value: MaybeSearchStrategy[Time | None] = None,
|
|
1320
|
+
max_value: MaybeSearchStrategy[Time | None] = None,
|
|
1321
|
+
) -> TimePeriod:
|
|
1322
|
+
"""Strategy for generating time periods."""
|
|
1335
1323
|
min_value_, max_value_ = [draw2(draw, v) for v in [min_value, max_value]]
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1324
|
+
strategy = times(min_value=min_value_, max_value=max_value_)
|
|
1325
|
+
start, end = draw(pairs(strategy, sorted=True))
|
|
1326
|
+
return TimePeriod(start, end)
|
|
1327
|
+
|
|
1328
|
+
|
|
1329
|
+
##
|
|
1330
|
+
|
|
1331
|
+
|
|
1332
|
+
@composite
|
|
1333
|
+
def times(
|
|
1334
|
+
draw: DrawFn,
|
|
1335
|
+
/,
|
|
1336
|
+
*,
|
|
1337
|
+
min_value: MaybeSearchStrategy[Time | None] = None,
|
|
1338
|
+
max_value: MaybeSearchStrategy[Time | None] = None,
|
|
1339
|
+
) -> Time:
|
|
1340
|
+
"""Strategy for generating times."""
|
|
1341
|
+
min_value_, max_value_ = [draw2(draw, v) for v in [min_value, max_value]]
|
|
1342
|
+
match min_value_:
|
|
1343
|
+
case None:
|
|
1344
|
+
min_value_ = Time.MIN
|
|
1345
|
+
case Time():
|
|
1346
|
+
...
|
|
1347
|
+
case never:
|
|
1348
|
+
assert_never(never)
|
|
1349
|
+
match max_value_:
|
|
1350
|
+
case None:
|
|
1351
|
+
max_value_ = Time.MAX
|
|
1352
|
+
case Time():
|
|
1353
|
+
...
|
|
1354
|
+
case never:
|
|
1355
|
+
assert_never(never)
|
|
1356
|
+
py_time = draw(
|
|
1357
|
+
hypothesis.strategies.times(
|
|
1358
|
+
min_value=min_value_.py_time(), max_value=max_value_.py_time()
|
|
1340
1359
|
)
|
|
1341
1360
|
)
|
|
1361
|
+
return Time.from_py_time(py_time)
|
|
1342
1362
|
|
|
1343
1363
|
|
|
1344
1364
|
##
|
|
1345
1365
|
|
|
1346
1366
|
|
|
1347
|
-
def triples(
|
|
1348
|
-
strategy: SearchStrategy[
|
|
1367
|
+
def triples[T](
|
|
1368
|
+
strategy: SearchStrategy[T],
|
|
1349
1369
|
/,
|
|
1350
1370
|
*,
|
|
1351
1371
|
unique: MaybeSearchStrategy[bool] = False,
|
|
1352
1372
|
sorted: MaybeSearchStrategy[bool] = False, # noqa: A002
|
|
1353
|
-
) -> SearchStrategy[tuple[
|
|
1373
|
+
) -> SearchStrategy[tuple[T, T, T]]:
|
|
1354
1374
|
"""Strategy for generating triples of elements."""
|
|
1355
1375
|
return lists_fixed_length(strategy, 3, unique=unique, sorted=sorted).map(
|
|
1356
1376
|
_triples_map
|
|
1357
1377
|
)
|
|
1358
1378
|
|
|
1359
1379
|
|
|
1360
|
-
def _triples_map(elements: list[
|
|
1380
|
+
def _triples_map[T](elements: list[T], /) -> tuple[T, T, T]:
|
|
1361
1381
|
first, second, third = elements
|
|
1362
1382
|
return first, second, third
|
|
1363
1383
|
|
|
@@ -1365,18 +1385,48 @@ def _triples_map(elements: list[_T], /) -> tuple[_T, _T, _T]:
|
|
|
1365
1385
|
##
|
|
1366
1386
|
|
|
1367
1387
|
|
|
1388
|
+
@composite
|
|
1389
|
+
def uint8s(
|
|
1390
|
+
draw: DrawFn,
|
|
1391
|
+
/,
|
|
1392
|
+
*,
|
|
1393
|
+
min_value: MaybeSearchStrategy[int | None] = None,
|
|
1394
|
+
max_value: MaybeSearchStrategy[int | None] = None,
|
|
1395
|
+
) -> int:
|
|
1396
|
+
"""Strategy for generating uint8s."""
|
|
1397
|
+
min_value_, max_value_ = [draw2(draw, v) for v in [min_value, max_value]]
|
|
1398
|
+
min_value_ = max_nullable([min_value_, MIN_UINT8])
|
|
1399
|
+
max_value_ = min_nullable([max_value_, MAX_UINT8])
|
|
1400
|
+
return draw(integers(min_value=min_value_, max_value=max_value_))
|
|
1401
|
+
|
|
1402
|
+
|
|
1403
|
+
@composite
|
|
1404
|
+
def uint16s(
|
|
1405
|
+
draw: DrawFn,
|
|
1406
|
+
/,
|
|
1407
|
+
*,
|
|
1408
|
+
min_value: MaybeSearchStrategy[int | None] = None,
|
|
1409
|
+
max_value: MaybeSearchStrategy[int | None] = None,
|
|
1410
|
+
) -> int:
|
|
1411
|
+
"""Strategy for generating uint16s."""
|
|
1412
|
+
min_value_, max_value_ = [draw2(draw, v) for v in [min_value, max_value]]
|
|
1413
|
+
min_value_ = max_nullable([min_value_, MIN_UINT16])
|
|
1414
|
+
max_value_ = min_nullable([max_value_, MAX_UINT16])
|
|
1415
|
+
return draw(integers(min_value=min_value_, max_value=max_value_))
|
|
1416
|
+
|
|
1417
|
+
|
|
1368
1418
|
@composite
|
|
1369
1419
|
def uint32s(
|
|
1370
1420
|
draw: DrawFn,
|
|
1371
1421
|
/,
|
|
1372
1422
|
*,
|
|
1373
|
-
min_value: MaybeSearchStrategy[int] =
|
|
1374
|
-
max_value: MaybeSearchStrategy[int] =
|
|
1423
|
+
min_value: MaybeSearchStrategy[int | None] = None,
|
|
1424
|
+
max_value: MaybeSearchStrategy[int | None] = None,
|
|
1375
1425
|
) -> int:
|
|
1376
1426
|
"""Strategy for generating uint32s."""
|
|
1377
1427
|
min_value_, max_value_ = [draw2(draw, v) for v in [min_value, max_value]]
|
|
1378
|
-
min_value_ =
|
|
1379
|
-
max_value_ =
|
|
1428
|
+
min_value_ = max_nullable([min_value_, MIN_UINT32])
|
|
1429
|
+
max_value_ = min_nullable([max_value_, MAX_UINT32])
|
|
1380
1430
|
return draw(integers(min_value=min_value_, max_value=max_value_))
|
|
1381
1431
|
|
|
1382
1432
|
|
|
@@ -1385,19 +1435,54 @@ def uint64s(
|
|
|
1385
1435
|
draw: DrawFn,
|
|
1386
1436
|
/,
|
|
1387
1437
|
*,
|
|
1388
|
-
min_value: MaybeSearchStrategy[int] =
|
|
1389
|
-
max_value: MaybeSearchStrategy[int] =
|
|
1438
|
+
min_value: MaybeSearchStrategy[int | None] = None,
|
|
1439
|
+
max_value: MaybeSearchStrategy[int | None] = None,
|
|
1390
1440
|
) -> int:
|
|
1391
1441
|
"""Strategy for generating uint64s."""
|
|
1392
1442
|
min_value_, max_value_ = [draw2(draw, v) for v in [min_value, max_value]]
|
|
1393
|
-
min_value_ =
|
|
1394
|
-
max_value_ =
|
|
1443
|
+
min_value_ = max_nullable([min_value_, MIN_UINT64])
|
|
1444
|
+
max_value_ = min_nullable([max_value_, MAX_UINT64])
|
|
1395
1445
|
return draw(integers(min_value=min_value_, max_value=max_value_))
|
|
1396
1446
|
|
|
1397
1447
|
|
|
1398
1448
|
##
|
|
1399
1449
|
|
|
1400
1450
|
|
|
1451
|
+
@composite
|
|
1452
|
+
def urls(
|
|
1453
|
+
draw: DrawFn,
|
|
1454
|
+
/,
|
|
1455
|
+
*,
|
|
1456
|
+
all_: MaybeSearchStrategy[bool] = False,
|
|
1457
|
+
username: MaybeSearchStrategy[bool] = False,
|
|
1458
|
+
password: MaybeSearchStrategy[bool] = False,
|
|
1459
|
+
host: MaybeSearchStrategy[bool] = False,
|
|
1460
|
+
port: MaybeSearchStrategy[bool] = False,
|
|
1461
|
+
database: MaybeSearchStrategy[bool] = False,
|
|
1462
|
+
) -> URL:
|
|
1463
|
+
from sqlalchemy import URL
|
|
1464
|
+
|
|
1465
|
+
have_all, have_username, have_password, have_host, have_port, have_database = [
|
|
1466
|
+
draw2(draw, b) for b in [all_, username, password, host, port, database]
|
|
1467
|
+
]
|
|
1468
|
+
username_use = draw(text_ascii(min_size=1)) if have_all or have_username else None
|
|
1469
|
+
password_use = draw(text_ascii(min_size=1)) if have_all or have_password else None
|
|
1470
|
+
host_use = draw(text_ascii(min_size=1)) if have_all or have_host else None
|
|
1471
|
+
port_use = draw(integers(min_value=1)) if have_all or have_port else None
|
|
1472
|
+
database_use = draw(text_ascii(min_size=1)) if have_all or have_database else None
|
|
1473
|
+
return URL.create(
|
|
1474
|
+
drivername="sqlite",
|
|
1475
|
+
username=username_use,
|
|
1476
|
+
password=password_use,
|
|
1477
|
+
host=host_use,
|
|
1478
|
+
port=port_use,
|
|
1479
|
+
database=database_use,
|
|
1480
|
+
)
|
|
1481
|
+
|
|
1482
|
+
|
|
1483
|
+
##
|
|
1484
|
+
|
|
1485
|
+
|
|
1401
1486
|
@composite
|
|
1402
1487
|
def versions(draw: DrawFn, /, *, suffix: MaybeSearchStrategy[bool] = False) -> Version:
|
|
1403
1488
|
"""Strategy for generating versions."""
|
|
@@ -1411,80 +1496,135 @@ def versions(draw: DrawFn, /, *, suffix: MaybeSearchStrategy[bool] = False) -> V
|
|
|
1411
1496
|
|
|
1412
1497
|
|
|
1413
1498
|
@composite
|
|
1414
|
-
def
|
|
1499
|
+
def year_months(
|
|
1415
1500
|
draw: DrawFn,
|
|
1416
1501
|
/,
|
|
1417
1502
|
*,
|
|
1418
|
-
min_value: MaybeSearchStrategy[
|
|
1419
|
-
max_value: MaybeSearchStrategy[
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1503
|
+
min_value: MaybeSearchStrategy[YearMonth | None] = None,
|
|
1504
|
+
max_value: MaybeSearchStrategy[YearMonth | None] = None,
|
|
1505
|
+
two_digit: MaybeSearchStrategy[bool] = False,
|
|
1506
|
+
) -> YearMonth:
|
|
1507
|
+
"""Strategy for generating months."""
|
|
1508
|
+
min_value_, max_value_ = [draw2(draw, v) for v in [min_value, max_value]]
|
|
1509
|
+
match min_value_:
|
|
1510
|
+
case None:
|
|
1511
|
+
min_value_ = YearMonth.MIN
|
|
1512
|
+
case YearMonth():
|
|
1513
|
+
...
|
|
1514
|
+
case never:
|
|
1515
|
+
assert_never(never)
|
|
1516
|
+
match max_value_:
|
|
1517
|
+
case None:
|
|
1518
|
+
max_value_ = YearMonth.MAX
|
|
1519
|
+
case YearMonth():
|
|
1520
|
+
...
|
|
1521
|
+
case never:
|
|
1522
|
+
assert_never(never)
|
|
1523
|
+
min_date, max_date = [m.on_day(1) for m in [min_value_, max_value_]]
|
|
1524
|
+
date = draw(dates(min_value=min_date, max_value=max_date, two_digit=two_digit))
|
|
1525
|
+
return date.year_month()
|
|
1432
1526
|
|
|
1527
|
+
|
|
1528
|
+
##
|
|
1529
|
+
|
|
1530
|
+
|
|
1531
|
+
@composite
|
|
1532
|
+
def zone_infos(draw: DrawFn, /) -> ZoneInfo:
|
|
1533
|
+
"""Strategy for generating time-zones."""
|
|
1534
|
+
time_zone = draw(timezones())
|
|
1535
|
+
if IS_LINUX: # skipif-not-linux
|
|
1536
|
+
_ = assume(time_zone.key not in _LINUX_DISALLOW_TIME_ZONES)
|
|
1537
|
+
with assume_does_not_raise(TimeZoneNotFoundError):
|
|
1538
|
+
_ = get_now(time_zone)
|
|
1539
|
+
return time_zone
|
|
1540
|
+
|
|
1541
|
+
|
|
1542
|
+
_LINUX_DISALLOW_TIME_ZONES: set[TimeZone | Literal["localtime"]] = {
|
|
1543
|
+
"Etc/UTC",
|
|
1544
|
+
"localtime",
|
|
1545
|
+
}
|
|
1546
|
+
|
|
1547
|
+
##
|
|
1548
|
+
|
|
1549
|
+
|
|
1550
|
+
@composite
|
|
1551
|
+
def zoned_date_time_periods(
|
|
1552
|
+
draw: DrawFn,
|
|
1553
|
+
/,
|
|
1554
|
+
*,
|
|
1555
|
+
min_value: MaybeSearchStrategy[PlainDateTime | ZonedDateTime | None] = None,
|
|
1556
|
+
max_value: MaybeSearchStrategy[PlainDateTime | ZonedDateTime | None] = None,
|
|
1557
|
+
time_zone: MaybeSearchStrategy[TimeZoneLike] = UTC,
|
|
1558
|
+
) -> ZonedDateTimePeriod:
|
|
1559
|
+
"""Strategy for generating zoned date-time periods."""
|
|
1433
1560
|
min_value_, max_value_ = [draw2(draw, v) for v in [min_value, max_value]]
|
|
1434
|
-
time_zone_ = draw2(draw, time_zone)
|
|
1435
|
-
|
|
1436
|
-
min_value_ =
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
if max_value_.tzinfo is None:
|
|
1441
|
-
max_value_ = max_value_.replace(tzinfo=time_zone_)
|
|
1442
|
-
else:
|
|
1443
|
-
with assume_does_not_raise(OverflowError, match="date value out of range"):
|
|
1444
|
-
max_value_ = max_value_.astimezone(time_zone_)
|
|
1445
|
-
try:
|
|
1446
|
-
datetime = draw(
|
|
1447
|
-
plain_datetimes(
|
|
1448
|
-
min_value=min_value_.replace(tzinfo=None),
|
|
1449
|
-
max_value=max_value_.replace(tzinfo=None),
|
|
1450
|
-
round_=round_,
|
|
1451
|
-
timedelta=timedelta,
|
|
1452
|
-
rel_tol=rel_tol,
|
|
1453
|
-
abs_tol=abs_tol,
|
|
1454
|
-
)
|
|
1455
|
-
)
|
|
1456
|
-
except PlainDateTimesError as error:
|
|
1457
|
-
raise ZonedDateTimesError(round_=error.round_) from None
|
|
1458
|
-
datetime = datetime.replace(tzinfo=time_zone_)
|
|
1459
|
-
_ = assume(min_value_ <= datetime <= max_value_)
|
|
1460
|
-
if valid:
|
|
1461
|
-
with assume_does_not_raise( # skipif-ci-and-windows
|
|
1462
|
-
CheckValidZonedDateTimeError
|
|
1463
|
-
):
|
|
1464
|
-
check_valid_zoned_datetime(datetime)
|
|
1465
|
-
return datetime
|
|
1561
|
+
time_zone_: TimeZoneLike = draw2(draw, time_zone)
|
|
1562
|
+
strategy = zoned_date_times(
|
|
1563
|
+
min_value=min_value_, max_value=max_value_, time_zone=time_zone_
|
|
1564
|
+
)
|
|
1565
|
+
start, end = draw(pairs(strategy, sorted=True))
|
|
1566
|
+
return ZonedDateTimePeriod(start, end)
|
|
1466
1567
|
|
|
1467
1568
|
|
|
1468
|
-
|
|
1469
|
-
class ZonedDateTimesError(Exception):
|
|
1470
|
-
round_: RoundMode
|
|
1569
|
+
##
|
|
1471
1570
|
|
|
1472
|
-
@override
|
|
1473
|
-
def __str__(self) -> str:
|
|
1474
|
-
return "Rounding requires a timedelta; got None"
|
|
1475
1571
|
|
|
1572
|
+
@composite
|
|
1573
|
+
def zoned_date_times(
|
|
1574
|
+
draw: DrawFn,
|
|
1575
|
+
/,
|
|
1576
|
+
*,
|
|
1577
|
+
min_value: MaybeSearchStrategy[PlainDateTime | ZonedDateTime | None] = None,
|
|
1578
|
+
max_value: MaybeSearchStrategy[PlainDateTime | ZonedDateTime | None] = None,
|
|
1579
|
+
time_zone: MaybeSearchStrategy[TimeZoneLike] = UTC,
|
|
1580
|
+
) -> ZonedDateTime:
|
|
1581
|
+
"""Strategy for generating zoned date-times."""
|
|
1582
|
+
min_value_, max_value_ = [draw2(draw, v) for v in [min_value, max_value]]
|
|
1583
|
+
time_zone_ = to_zone_info(draw2(draw, time_zone))
|
|
1584
|
+
match min_value_:
|
|
1585
|
+
case None | PlainDateTime():
|
|
1586
|
+
...
|
|
1587
|
+
case ZonedDateTime():
|
|
1588
|
+
with assume_does_not_raise(ValueError):
|
|
1589
|
+
min_value_ = min_value_.to_tz(time_zone_.key).to_plain()
|
|
1590
|
+
case never:
|
|
1591
|
+
assert_never(never)
|
|
1592
|
+
match max_value_:
|
|
1593
|
+
case None | PlainDateTime():
|
|
1594
|
+
...
|
|
1595
|
+
case ZonedDateTime():
|
|
1596
|
+
with assume_does_not_raise(ValueError):
|
|
1597
|
+
max_value_ = max_value_.to_tz(time_zone_.key).to_plain()
|
|
1598
|
+
case never:
|
|
1599
|
+
assert_never(never)
|
|
1600
|
+
plain = draw(plain_date_times(min_value=min_value_, max_value=max_value_))
|
|
1601
|
+
with (
|
|
1602
|
+
assume_does_not_raise(RepeatedTime),
|
|
1603
|
+
assume_does_not_raise(SkippedTime),
|
|
1604
|
+
assume_does_not_raise(ValueError, match=r"Resulting time is out of range"),
|
|
1605
|
+
):
|
|
1606
|
+
zoned = plain.assume_tz(time_zone_.key, disambiguate="raise")
|
|
1607
|
+
with assume_does_not_raise(OverflowError, match=r"date value out of range"):
|
|
1608
|
+
if not ((Date.MIN + DAY) <= zoned.date() <= (Date.MAX - DAY)):
|
|
1609
|
+
_ = zoned.py_datetime()
|
|
1610
|
+
return zoned
|
|
1611
|
+
|
|
1612
|
+
|
|
1613
|
+
zoned_date_times_2000 = zoned_date_times(
|
|
1614
|
+
min_value=ZonedDateTime(2000, 1, 1, tz=UTC.key),
|
|
1615
|
+
max_value=ZonedDateTime(2000, 12, 31, tz=UTC.key),
|
|
1616
|
+
)
|
|
1476
1617
|
|
|
1477
1618
|
__all__ = [
|
|
1478
1619
|
"Draw2Error",
|
|
1479
1620
|
"MaybeSearchStrategy",
|
|
1480
|
-
"PlainDateTimesError",
|
|
1481
1621
|
"Shape",
|
|
1482
|
-
"ZonedDateTimesError",
|
|
1483
1622
|
"assume_does_not_raise",
|
|
1484
1623
|
"bool_arrays",
|
|
1485
|
-
"
|
|
1486
|
-
"
|
|
1487
|
-
"
|
|
1624
|
+
"date_deltas",
|
|
1625
|
+
"date_periods",
|
|
1626
|
+
"date_time_deltas",
|
|
1627
|
+
"dates",
|
|
1488
1628
|
"draw2",
|
|
1489
1629
|
"float32s",
|
|
1490
1630
|
"float64s",
|
|
@@ -1492,27 +1632,27 @@ __all__ = [
|
|
|
1492
1632
|
"floats_extra",
|
|
1493
1633
|
"git_repos",
|
|
1494
1634
|
"hashables",
|
|
1635
|
+
"import_froms",
|
|
1636
|
+
"imports",
|
|
1637
|
+
"int8s",
|
|
1638
|
+
"int16s",
|
|
1495
1639
|
"int32s",
|
|
1496
1640
|
"int64s",
|
|
1497
1641
|
"int_arrays",
|
|
1498
1642
|
"lists_fixed_length",
|
|
1499
|
-
"
|
|
1500
|
-
"min_and_maybe_max_datetimes",
|
|
1501
|
-
"min_and_maybe_max_sizes",
|
|
1502
|
-
"min_and_maybe_max_sizes",
|
|
1503
|
-
"months",
|
|
1504
|
-
"namespace_mixins",
|
|
1643
|
+
"month_days",
|
|
1505
1644
|
"numbers",
|
|
1506
1645
|
"pairs",
|
|
1507
1646
|
"paths",
|
|
1508
|
-
"
|
|
1509
|
-
"
|
|
1647
|
+
"permissions",
|
|
1648
|
+
"plain_date_times",
|
|
1649
|
+
"py_datetimes",
|
|
1650
|
+
"quadruples",
|
|
1510
1651
|
"random_states",
|
|
1511
1652
|
"sentinels",
|
|
1512
1653
|
"sets_fixed_length",
|
|
1513
1654
|
"setup_hypothesis_profiles",
|
|
1514
1655
|
"slices",
|
|
1515
|
-
"sqlalchemy_engines",
|
|
1516
1656
|
"str_arrays",
|
|
1517
1657
|
"temp_dirs",
|
|
1518
1658
|
"temp_paths",
|
|
@@ -1522,10 +1662,19 @@ __all__ = [
|
|
|
1522
1662
|
"text_clean",
|
|
1523
1663
|
"text_digits",
|
|
1524
1664
|
"text_printable",
|
|
1525
|
-
"
|
|
1665
|
+
"time_deltas",
|
|
1666
|
+
"time_periods",
|
|
1667
|
+
"times",
|
|
1526
1668
|
"triples",
|
|
1669
|
+
"uint8s",
|
|
1670
|
+
"uint16s",
|
|
1527
1671
|
"uint32s",
|
|
1528
1672
|
"uint64s",
|
|
1673
|
+
"urls",
|
|
1529
1674
|
"versions",
|
|
1530
|
-
"
|
|
1675
|
+
"year_months",
|
|
1676
|
+
"zone_infos",
|
|
1677
|
+
"zoned_date_time_periods",
|
|
1678
|
+
"zoned_date_times",
|
|
1679
|
+
"zoned_date_times_2000",
|
|
1531
1680
|
]
|