dycw-utilities 0.135.0__py3-none-any.whl → 0.178.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.
Potentially problematic release.
This version of dycw-utilities might be problematic. Click here for more details.
- dycw_utilities-0.178.1.dist-info/METADATA +34 -0
- dycw_utilities-0.178.1.dist-info/RECORD +105 -0
- dycw_utilities-0.178.1.dist-info/WHEEL +4 -0
- dycw_utilities-0.178.1.dist-info/entry_points.txt +4 -0
- utilities/__init__.py +1 -1
- utilities/altair.py +13 -10
- utilities/asyncio.py +312 -787
- utilities/atomicwrites.py +18 -6
- utilities/atools.py +64 -4
- utilities/cachetools.py +9 -6
- utilities/click.py +195 -77
- utilities/concurrent.py +1 -1
- utilities/contextlib.py +216 -17
- utilities/contextvars.py +20 -1
- utilities/cryptography.py +3 -3
- utilities/dataclasses.py +15 -28
- utilities/docker.py +387 -0
- utilities/enum.py +2 -2
- utilities/errors.py +17 -3
- utilities/fastapi.py +28 -59
- utilities/fpdf2.py +2 -2
- utilities/functions.py +24 -269
- utilities/git.py +9 -30
- utilities/grp.py +28 -0
- utilities/gzip.py +31 -0
- utilities/http.py +3 -2
- utilities/hypothesis.py +513 -159
- utilities/importlib.py +17 -1
- utilities/inflect.py +12 -4
- utilities/iterables.py +33 -58
- utilities/jinja2.py +148 -0
- utilities/json.py +70 -0
- utilities/libcst.py +38 -17
- utilities/lightweight_charts.py +4 -7
- utilities/logging.py +136 -93
- utilities/math.py +8 -4
- utilities/more_itertools.py +43 -45
- utilities/operator.py +27 -27
- utilities/orjson.py +189 -36
- utilities/os.py +61 -4
- utilities/packaging.py +115 -0
- utilities/parse.py +8 -5
- utilities/pathlib.py +269 -40
- utilities/permissions.py +298 -0
- utilities/platform.py +7 -6
- utilities/polars.py +1205 -413
- utilities/polars_ols.py +1 -1
- utilities/postgres.py +408 -0
- utilities/pottery.py +43 -19
- utilities/pqdm.py +3 -3
- utilities/psutil.py +5 -57
- utilities/pwd.py +28 -0
- utilities/pydantic.py +4 -52
- utilities/pydantic_settings.py +240 -0
- utilities/pydantic_settings_sops.py +76 -0
- utilities/pyinstrument.py +7 -7
- utilities/pytest.py +104 -143
- 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 +11 -6
- utilities/re.py +1 -1
- utilities/redis.py +220 -343
- utilities/sentinel.py +10 -0
- utilities/shelve.py +4 -1
- utilities/shutil.py +25 -0
- utilities/slack_sdk.py +35 -104
- utilities/sqlalchemy.py +496 -471
- utilities/sqlalchemy_polars.py +29 -54
- utilities/string.py +2 -3
- utilities/subprocess.py +1977 -0
- utilities/tempfile.py +112 -4
- utilities/testbook.py +50 -0
- utilities/text.py +174 -42
- utilities/throttle.py +158 -0
- utilities/timer.py +2 -2
- utilities/traceback.py +70 -35
- utilities/types.py +102 -30
- utilities/typing.py +479 -19
- utilities/uuid.py +42 -5
- utilities/version.py +27 -26
- utilities/whenever.py +1559 -361
- utilities/zoneinfo.py +80 -22
- dycw_utilities-0.135.0.dist-info/METADATA +0 -39
- dycw_utilities-0.135.0.dist-info/RECORD +0 -96
- dycw_utilities-0.135.0.dist-info/WHEEL +0 -4
- dycw_utilities-0.135.0.dist-info/licenses/LICENSE +0 -21
- utilities/aiolimiter.py +0 -25
- utilities/arq.py +0 -216
- utilities/eventkit.py +0 -388
- utilities/luigi.py +0 -183
- utilities/period.py +0 -152
- utilities/pudb.py +0 -62
- utilities/python_dotenv.py +0 -101
- utilities/streamlit.py +0 -105
- utilities/typed_settings.py +0 -123
utilities/hypothesis.py
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import builtins
|
|
4
|
+
import datetime as dt
|
|
4
5
|
from contextlib import contextmanager
|
|
5
6
|
from dataclasses import dataclass
|
|
6
7
|
from enum import Enum, auto
|
|
@@ -31,6 +32,7 @@ from hypothesis.strategies import (
|
|
|
31
32
|
sampled_from,
|
|
32
33
|
sets,
|
|
33
34
|
text,
|
|
35
|
+
timezones,
|
|
34
36
|
uuids,
|
|
35
37
|
)
|
|
36
38
|
from hypothesis.utils.conventions import not_set
|
|
@@ -38,46 +40,53 @@ from whenever import (
|
|
|
38
40
|
Date,
|
|
39
41
|
DateDelta,
|
|
40
42
|
DateTimeDelta,
|
|
43
|
+
MonthDay,
|
|
41
44
|
PlainDateTime,
|
|
42
45
|
RepeatedTime,
|
|
43
46
|
SkippedTime,
|
|
44
47
|
Time,
|
|
45
48
|
TimeDelta,
|
|
46
49
|
TimeZoneNotFoundError,
|
|
50
|
+
YearMonth,
|
|
47
51
|
ZonedDateTime,
|
|
48
52
|
)
|
|
49
53
|
|
|
50
|
-
from utilities.functions import ensure_int, ensure_str
|
|
54
|
+
from utilities.functions import ensure_int, ensure_str, max_nullable, min_nullable
|
|
51
55
|
from utilities.math import (
|
|
52
56
|
MAX_FLOAT32,
|
|
53
57
|
MAX_FLOAT64,
|
|
58
|
+
MAX_INT8,
|
|
59
|
+
MAX_INT16,
|
|
54
60
|
MAX_INT32,
|
|
55
61
|
MAX_INT64,
|
|
62
|
+
MAX_UINT8,
|
|
63
|
+
MAX_UINT16,
|
|
56
64
|
MAX_UINT32,
|
|
57
65
|
MAX_UINT64,
|
|
58
66
|
MIN_FLOAT32,
|
|
59
67
|
MIN_FLOAT64,
|
|
68
|
+
MIN_INT8,
|
|
69
|
+
MIN_INT16,
|
|
60
70
|
MIN_INT32,
|
|
61
71
|
MIN_INT64,
|
|
72
|
+
MIN_UINT8,
|
|
73
|
+
MIN_UINT16,
|
|
62
74
|
MIN_UINT32,
|
|
63
75
|
MIN_UINT64,
|
|
64
76
|
is_zero,
|
|
65
77
|
)
|
|
66
78
|
from utilities.os import get_env_var
|
|
67
|
-
from utilities.pathlib import temp_cwd
|
|
68
|
-
from utilities.
|
|
69
|
-
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
|
|
70
83
|
from utilities.tempfile import TEMP_DIR, TemporaryDirectory
|
|
71
|
-
from utilities.types import DateTimeRoundUnit
|
|
72
|
-
from utilities.typing import get_literal_elements
|
|
73
84
|
from utilities.version import Version
|
|
74
85
|
from utilities.whenever import (
|
|
75
86
|
DATE_DELTA_MAX,
|
|
76
87
|
DATE_DELTA_MIN,
|
|
77
88
|
DATE_DELTA_PARSABLE_MAX,
|
|
78
89
|
DATE_DELTA_PARSABLE_MIN,
|
|
79
|
-
DATE_MAX,
|
|
80
|
-
DATE_MIN,
|
|
81
90
|
DATE_TIME_DELTA_MAX,
|
|
82
91
|
DATE_TIME_DELTA_MIN,
|
|
83
92
|
DATE_TIME_DELTA_PARSABLE_MAX,
|
|
@@ -85,31 +94,29 @@ from utilities.whenever import (
|
|
|
85
94
|
DATE_TWO_DIGIT_YEAR_MAX,
|
|
86
95
|
DATE_TWO_DIGIT_YEAR_MIN,
|
|
87
96
|
DAY,
|
|
88
|
-
MONTH_MAX,
|
|
89
|
-
MONTH_MIN,
|
|
90
|
-
PLAIN_DATE_TIME_MAX,
|
|
91
|
-
PLAIN_DATE_TIME_MIN,
|
|
92
97
|
TIME_DELTA_MAX,
|
|
93
98
|
TIME_DELTA_MIN,
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
99
|
+
DatePeriod,
|
|
100
|
+
TimePeriod,
|
|
101
|
+
ZonedDateTimePeriod,
|
|
102
|
+
get_now,
|
|
98
103
|
to_date_time_delta,
|
|
99
104
|
to_days,
|
|
100
|
-
|
|
105
|
+
to_nanoseconds,
|
|
101
106
|
)
|
|
102
|
-
from utilities.zoneinfo import UTC,
|
|
107
|
+
from utilities.zoneinfo import UTC, to_zone_info
|
|
103
108
|
|
|
104
109
|
if TYPE_CHECKING:
|
|
105
|
-
import datetime as dt
|
|
106
110
|
from collections.abc import Collection, Hashable, Iterable, Iterator
|
|
111
|
+
from zoneinfo import ZoneInfo
|
|
107
112
|
|
|
108
113
|
from hypothesis.database import ExampleDatabase
|
|
114
|
+
from libcst import Import, ImportFrom
|
|
109
115
|
from numpy.random import RandomState
|
|
116
|
+
from sqlalchemy import URL
|
|
110
117
|
|
|
111
118
|
from utilities.numpy import NDArrayB, NDArrayF, NDArrayI, NDArrayO
|
|
112
|
-
from utilities.types import Number, TimeZoneLike
|
|
119
|
+
from utilities.types import Number, TimeZone, TimeZoneLike
|
|
113
120
|
|
|
114
121
|
|
|
115
122
|
type MaybeSearchStrategy[_T] = _T | SearchStrategy[_T]
|
|
@@ -184,14 +191,14 @@ def date_deltas(
|
|
|
184
191
|
min_value_ = DATE_DELTA_MIN
|
|
185
192
|
case DateDelta():
|
|
186
193
|
...
|
|
187
|
-
case
|
|
194
|
+
case never:
|
|
188
195
|
assert_never(never)
|
|
189
196
|
match max_value_:
|
|
190
197
|
case None:
|
|
191
198
|
max_value_ = DATE_DELTA_MAX
|
|
192
199
|
case DateDelta():
|
|
193
200
|
...
|
|
194
|
-
case
|
|
201
|
+
case never:
|
|
195
202
|
assert_never(never)
|
|
196
203
|
min_days = to_days(min_value_)
|
|
197
204
|
max_days = to_days(max_value_)
|
|
@@ -205,6 +212,26 @@ def date_deltas(
|
|
|
205
212
|
##
|
|
206
213
|
|
|
207
214
|
|
|
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)
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
##
|
|
233
|
+
|
|
234
|
+
|
|
208
235
|
@composite
|
|
209
236
|
def date_time_deltas(
|
|
210
237
|
draw: DrawFn,
|
|
@@ -213,6 +240,7 @@ def date_time_deltas(
|
|
|
213
240
|
min_value: MaybeSearchStrategy[DateTimeDelta | None] = None,
|
|
214
241
|
max_value: MaybeSearchStrategy[DateTimeDelta | None] = None,
|
|
215
242
|
parsable: MaybeSearchStrategy[bool] = False,
|
|
243
|
+
nativable: MaybeSearchStrategy[bool] = False,
|
|
216
244
|
) -> DateTimeDelta:
|
|
217
245
|
"""Strategy for generating date deltas."""
|
|
218
246
|
min_value_, max_value_ = [draw2(draw, v) for v in [min_value, max_value]]
|
|
@@ -221,20 +249,26 @@ def date_time_deltas(
|
|
|
221
249
|
min_value_ = DATE_TIME_DELTA_MIN
|
|
222
250
|
case DateTimeDelta():
|
|
223
251
|
...
|
|
224
|
-
case
|
|
252
|
+
case never:
|
|
225
253
|
assert_never(never)
|
|
226
254
|
match max_value_:
|
|
227
255
|
case None:
|
|
228
256
|
max_value_ = DATE_TIME_DELTA_MAX
|
|
229
257
|
case DateTimeDelta():
|
|
230
258
|
...
|
|
231
|
-
case
|
|
259
|
+
case never:
|
|
232
260
|
assert_never(never)
|
|
233
|
-
min_nanos, max_nanos = map(
|
|
261
|
+
min_nanos, max_nanos = map(to_nanoseconds, [min_value_, max_value_])
|
|
234
262
|
if draw2(draw, parsable):
|
|
235
|
-
min_nanos = max(min_nanos,
|
|
236
|
-
max_nanos = min(max_nanos,
|
|
237
|
-
|
|
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))
|
|
238
272
|
return to_date_time_delta(nanos)
|
|
239
273
|
|
|
240
274
|
|
|
@@ -254,17 +288,17 @@ def dates(
|
|
|
254
288
|
min_value_, max_value_ = [draw2(draw, v) for v in [min_value, max_value]]
|
|
255
289
|
match min_value_:
|
|
256
290
|
case None:
|
|
257
|
-
min_value_ =
|
|
291
|
+
min_value_ = Date.MIN
|
|
258
292
|
case Date():
|
|
259
293
|
...
|
|
260
|
-
case
|
|
294
|
+
case never:
|
|
261
295
|
assert_never(never)
|
|
262
296
|
match max_value_:
|
|
263
297
|
case None:
|
|
264
|
-
max_value_ =
|
|
298
|
+
max_value_ = Date.MAX
|
|
265
299
|
case Date():
|
|
266
300
|
...
|
|
267
|
-
case
|
|
301
|
+
case never:
|
|
268
302
|
assert_never(never)
|
|
269
303
|
if draw2(draw, two_digit):
|
|
270
304
|
min_value_ = max(min_value_, DATE_TWO_DIGIT_YEAR_MIN)
|
|
@@ -333,21 +367,21 @@ def draw2[T](
|
|
|
333
367
|
return value
|
|
334
368
|
case None, SearchStrategy(), False:
|
|
335
369
|
value2 = draw(default)
|
|
336
|
-
if
|
|
370
|
+
if is_sentinel(value2):
|
|
337
371
|
raise _Draw2DefaultGeneratedSentinelError
|
|
338
372
|
return value2
|
|
339
373
|
case Sentinel(), None, _:
|
|
340
374
|
raise _Draw2InputResolvedToSentinelError
|
|
341
375
|
case Sentinel(), SearchStrategy(), True:
|
|
342
376
|
value2 = draw(default)
|
|
343
|
-
if
|
|
377
|
+
if is_sentinel(value2):
|
|
344
378
|
raise _Draw2DefaultGeneratedSentinelError
|
|
345
379
|
return value2
|
|
346
380
|
case Sentinel(), SearchStrategy(), False:
|
|
347
381
|
raise _Draw2InputResolvedToSentinelError
|
|
348
382
|
case _, _, _:
|
|
349
383
|
return value
|
|
350
|
-
case
|
|
384
|
+
case never:
|
|
351
385
|
assert_never(never)
|
|
352
386
|
|
|
353
387
|
|
|
@@ -377,16 +411,27 @@ def float32s(
|
|
|
377
411
|
draw: DrawFn,
|
|
378
412
|
/,
|
|
379
413
|
*,
|
|
380
|
-
min_value: MaybeSearchStrategy[float] =
|
|
381
|
-
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,
|
|
382
418
|
) -> float:
|
|
383
419
|
"""Strategy for generating float32s."""
|
|
384
420
|
min_value_, max_value_ = [draw2(draw, v) for v in [min_value, max_value]]
|
|
385
|
-
min_value_ =
|
|
386
|
-
max_value_ =
|
|
421
|
+
min_value_ = max_nullable([min_value_, MIN_FLOAT32])
|
|
422
|
+
max_value_ = min_nullable([max_value_, MAX_FLOAT32])
|
|
387
423
|
if is_zero(min_value_) and is_zero(max_value_):
|
|
388
424
|
min_value_ = max_value_ = 0.0
|
|
389
|
-
|
|
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
|
+
)
|
|
390
435
|
|
|
391
436
|
|
|
392
437
|
@composite
|
|
@@ -394,16 +439,27 @@ def float64s(
|
|
|
394
439
|
draw: DrawFn,
|
|
395
440
|
/,
|
|
396
441
|
*,
|
|
397
|
-
min_value: MaybeSearchStrategy[float] =
|
|
398
|
-
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,
|
|
399
446
|
) -> float:
|
|
400
447
|
"""Strategy for generating float64s."""
|
|
401
448
|
min_value_, max_value_ = [draw2(draw, v) for v in [min_value, max_value]]
|
|
402
|
-
min_value_ =
|
|
403
|
-
max_value_ =
|
|
449
|
+
min_value_ = max_nullable([min_value_, MIN_FLOAT64])
|
|
450
|
+
max_value_ = min_nullable([max_value_, MAX_FLOAT64])
|
|
404
451
|
if is_zero(min_value_) and is_zero(max_value_):
|
|
405
452
|
min_value_ = max_value_ = 0.0
|
|
406
|
-
|
|
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
|
+
)
|
|
407
463
|
|
|
408
464
|
|
|
409
465
|
##
|
|
@@ -495,38 +551,6 @@ def floats_extra(
|
|
|
495
551
|
##
|
|
496
552
|
|
|
497
553
|
|
|
498
|
-
@composite
|
|
499
|
-
def freqs(
|
|
500
|
-
draw: DrawFn, /, *, unit: MaybeSearchStrategy[DateTimeRoundUnit | None] = None
|
|
501
|
-
) -> Freq:
|
|
502
|
-
unit_ = draw2(draw, unit, _freq_units())
|
|
503
|
-
match unit_:
|
|
504
|
-
case "day":
|
|
505
|
-
return Freq(unit=unit_)
|
|
506
|
-
case "hour":
|
|
507
|
-
return Freq(unit=unit_, increment=draw(_freq_increments(24)))
|
|
508
|
-
case "minute" | "second":
|
|
509
|
-
return Freq(unit=unit_, increment=draw(_freq_increments(60)))
|
|
510
|
-
case "millisecond" | "microsecond" | "nanosecond":
|
|
511
|
-
return Freq(unit=unit_, increment=draw(_freq_increments(1000)))
|
|
512
|
-
case _ as never:
|
|
513
|
-
assert_never(never)
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
@composite
|
|
517
|
-
def _freq_units(draw: DrawFn, /) -> DateTimeRoundUnit:
|
|
518
|
-
return draw(sampled_from(get_literal_elements(DateTimeRoundUnit)))
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
@composite
|
|
522
|
-
def _freq_increments(draw: DrawFn, n: int, /) -> int:
|
|
523
|
-
divisors = [i for i in range(1, n) if n % i == 0]
|
|
524
|
-
return draw(sampled_from(divisors))
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
##
|
|
528
|
-
|
|
529
|
-
|
|
530
554
|
@composite
|
|
531
555
|
def git_repos(draw: DrawFn, /) -> Path:
|
|
532
556
|
path = draw(temp_paths())
|
|
@@ -555,6 +579,59 @@ def hashables() -> SearchStrategy[Hashable]:
|
|
|
555
579
|
##
|
|
556
580
|
|
|
557
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
|
+
|
|
558
635
|
@composite
|
|
559
636
|
def int_arrays(
|
|
560
637
|
draw: DrawFn,
|
|
@@ -584,18 +661,48 @@ def int_arrays(
|
|
|
584
661
|
##
|
|
585
662
|
|
|
586
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
|
+
|
|
587
694
|
@composite
|
|
588
695
|
def int32s(
|
|
589
696
|
draw: DrawFn,
|
|
590
697
|
/,
|
|
591
698
|
*,
|
|
592
|
-
min_value: MaybeSearchStrategy[int] =
|
|
593
|
-
max_value: MaybeSearchStrategy[int] =
|
|
699
|
+
min_value: MaybeSearchStrategy[int | None] = None,
|
|
700
|
+
max_value: MaybeSearchStrategy[int | None] = None,
|
|
594
701
|
) -> int:
|
|
595
702
|
"""Strategy for generating int32s."""
|
|
596
703
|
min_value_, max_value_ = [draw2(draw, v) for v in [min_value, max_value]]
|
|
597
|
-
min_value_ =
|
|
598
|
-
max_value_ =
|
|
704
|
+
min_value_ = max_nullable([min_value_, MIN_INT32])
|
|
705
|
+
max_value_ = min_nullable([max_value_, MAX_INT32])
|
|
599
706
|
return draw(integers(min_value_, max_value_))
|
|
600
707
|
|
|
601
708
|
|
|
@@ -604,13 +711,13 @@ def int64s(
|
|
|
604
711
|
draw: DrawFn,
|
|
605
712
|
/,
|
|
606
713
|
*,
|
|
607
|
-
min_value: MaybeSearchStrategy[int] =
|
|
608
|
-
max_value: MaybeSearchStrategy[int] =
|
|
714
|
+
min_value: MaybeSearchStrategy[int | None] = None,
|
|
715
|
+
max_value: MaybeSearchStrategy[int | None] = None,
|
|
609
716
|
) -> int:
|
|
610
717
|
"""Strategy for generating int64s."""
|
|
611
718
|
min_value_, max_value_ = [draw2(draw, v) for v in [min_value, max_value]]
|
|
612
|
-
min_value_ =
|
|
613
|
-
max_value_ =
|
|
719
|
+
min_value_ = max_nullable([min_value_, MIN_INT64])
|
|
720
|
+
max_value_ = min_nullable([max_value_, MAX_INT64])
|
|
614
721
|
return draw(integers(min_value_, max_value_))
|
|
615
722
|
|
|
616
723
|
|
|
@@ -641,47 +748,32 @@ def lists_fixed_length[T](
|
|
|
641
748
|
|
|
642
749
|
|
|
643
750
|
@composite
|
|
644
|
-
def
|
|
751
|
+
def month_days(
|
|
645
752
|
draw: DrawFn,
|
|
646
753
|
/,
|
|
647
754
|
*,
|
|
648
|
-
min_value: MaybeSearchStrategy[
|
|
649
|
-
max_value: MaybeSearchStrategy[
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
"""Strategy for generating months."""
|
|
755
|
+
min_value: MaybeSearchStrategy[MonthDay | None] = None,
|
|
756
|
+
max_value: MaybeSearchStrategy[MonthDay | None] = None,
|
|
757
|
+
) -> MonthDay:
|
|
758
|
+
"""Strategy for generating month-days."""
|
|
653
759
|
min_value_, max_value_ = [draw2(draw, v) for v in [min_value, max_value]]
|
|
654
760
|
match min_value_:
|
|
655
761
|
case None:
|
|
656
|
-
min_value_ =
|
|
657
|
-
case
|
|
762
|
+
min_value_ = MonthDay.MIN
|
|
763
|
+
case MonthDay():
|
|
658
764
|
...
|
|
659
|
-
case
|
|
765
|
+
case never:
|
|
660
766
|
assert_never(never)
|
|
661
767
|
match max_value_:
|
|
662
768
|
case None:
|
|
663
|
-
max_value_ =
|
|
664
|
-
case
|
|
769
|
+
max_value_ = MonthDay.MAX
|
|
770
|
+
case MonthDay():
|
|
665
771
|
...
|
|
666
|
-
case
|
|
772
|
+
case never:
|
|
667
773
|
assert_never(never)
|
|
668
|
-
min_date, max_date = [m.
|
|
669
|
-
date = draw(dates(min_value=min_date, max_value=max_date
|
|
670
|
-
return
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
##
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
@composite
|
|
677
|
-
def namespace_mixins(draw: DrawFn, /) -> type:
|
|
678
|
-
"""Strategy for generating task namespace mixins."""
|
|
679
|
-
path = draw(temp_paths())
|
|
680
|
-
|
|
681
|
-
class NamespaceMixin:
|
|
682
|
-
task_namespace = path.name
|
|
683
|
-
|
|
684
|
-
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()
|
|
685
777
|
|
|
686
778
|
|
|
687
779
|
##
|
|
@@ -746,18 +838,67 @@ def _pairs_map[T](elements: list[T], /) -> tuple[T, T]:
|
|
|
746
838
|
##
|
|
747
839
|
|
|
748
840
|
|
|
749
|
-
|
|
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:
|
|
750
849
|
"""Strategy for generating `Path`s."""
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
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
|
|
863
|
+
|
|
864
|
+
|
|
865
|
+
##
|
|
866
|
+
|
|
867
|
+
|
|
868
|
+
@composite
|
|
869
|
+
def permissions(
|
|
870
|
+
draw: DrawFn,
|
|
871
|
+
/,
|
|
872
|
+
*,
|
|
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
|
+
)
|
|
754
895
|
|
|
755
896
|
|
|
756
897
|
##
|
|
757
898
|
|
|
758
899
|
|
|
759
900
|
@composite
|
|
760
|
-
def
|
|
901
|
+
def plain_date_times(
|
|
761
902
|
draw: DrawFn,
|
|
762
903
|
/,
|
|
763
904
|
*,
|
|
@@ -768,17 +909,17 @@ def plain_datetimes(
|
|
|
768
909
|
min_value_, max_value_ = [draw2(draw, v) for v in [min_value, max_value]]
|
|
769
910
|
match min_value_:
|
|
770
911
|
case None:
|
|
771
|
-
min_value_ =
|
|
912
|
+
min_value_ = PlainDateTime.MIN
|
|
772
913
|
case PlainDateTime():
|
|
773
914
|
...
|
|
774
|
-
case
|
|
915
|
+
case never:
|
|
775
916
|
assert_never(never)
|
|
776
917
|
match max_value_:
|
|
777
918
|
case None:
|
|
778
|
-
max_value_ =
|
|
919
|
+
max_value_ = PlainDateTime.MAX
|
|
779
920
|
case PlainDateTime():
|
|
780
921
|
...
|
|
781
|
-
case
|
|
922
|
+
case never:
|
|
782
923
|
assert_never(never)
|
|
783
924
|
py_datetime = draw(
|
|
784
925
|
datetimes(
|
|
@@ -791,6 +932,46 @@ def plain_datetimes(
|
|
|
791
932
|
##
|
|
792
933
|
|
|
793
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
|
+
)
|
|
949
|
+
|
|
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
|
|
970
|
+
|
|
971
|
+
|
|
972
|
+
##
|
|
973
|
+
|
|
974
|
+
|
|
794
975
|
@composite
|
|
795
976
|
def random_states(
|
|
796
977
|
draw: DrawFn, /, *, seed: MaybeSearchStrategy[int | None] = None
|
|
@@ -798,7 +979,7 @@ def random_states(
|
|
|
798
979
|
"""Strategy for generating `numpy` random states."""
|
|
799
980
|
from numpy.random import RandomState
|
|
800
981
|
|
|
801
|
-
seed_ = draw2(draw, seed,
|
|
982
|
+
seed_ = draw2(draw, seed, uint32s())
|
|
802
983
|
return RandomState(seed=seed_)
|
|
803
984
|
|
|
804
985
|
|
|
@@ -845,7 +1026,7 @@ def setup_hypothesis_profiles(
|
|
|
845
1026
|
return 100
|
|
846
1027
|
case Profile.ci:
|
|
847
1028
|
return 1000
|
|
848
|
-
case
|
|
1029
|
+
case never:
|
|
849
1030
|
assert_never(never)
|
|
850
1031
|
|
|
851
1032
|
@property
|
|
@@ -855,11 +1036,11 @@ def setup_hypothesis_profiles(
|
|
|
855
1036
|
return Verbosity.quiet
|
|
856
1037
|
case Profile.ci:
|
|
857
1038
|
return Verbosity.verbose
|
|
858
|
-
case
|
|
1039
|
+
case never:
|
|
859
1040
|
assert_never(never)
|
|
860
1041
|
|
|
861
1042
|
phases = {Phase.explicit, Phase.reuse, Phase.generate, Phase.target}
|
|
862
|
-
if "HYPOTHESIS_NO_SHRINK" not in environ:
|
|
1043
|
+
if "HYPOTHESIS_NO_SHRINK" not in environ: # pragma: no cover
|
|
863
1044
|
phases.add(Phase.shrink)
|
|
864
1045
|
for profile in Profile:
|
|
865
1046
|
try:
|
|
@@ -980,9 +1161,7 @@ def temp_dirs(draw: DrawFn, /) -> TemporaryDirectory:
|
|
|
980
1161
|
"""Search strategy for temporary directories."""
|
|
981
1162
|
_TEMP_DIR_HYPOTHESIS.mkdir(exist_ok=True)
|
|
982
1163
|
uuid = draw(uuids())
|
|
983
|
-
return TemporaryDirectory(
|
|
984
|
-
prefix=f"{uuid}__", dir=_TEMP_DIR_HYPOTHESIS, ignore_cleanup_errors=IS_WINDOWS
|
|
985
|
-
)
|
|
1164
|
+
return TemporaryDirectory(prefix=f"{uuid}__", dir=_TEMP_DIR_HYPOTHESIS)
|
|
986
1165
|
|
|
987
1166
|
|
|
988
1167
|
##
|
|
@@ -1112,14 +1291,14 @@ def time_deltas(
|
|
|
1112
1291
|
min_value_ = TIME_DELTA_MIN
|
|
1113
1292
|
case TimeDelta():
|
|
1114
1293
|
...
|
|
1115
|
-
case
|
|
1294
|
+
case never:
|
|
1116
1295
|
assert_never(never)
|
|
1117
1296
|
match max_value_:
|
|
1118
1297
|
case None:
|
|
1119
1298
|
max_value_ = TIME_DELTA_MAX
|
|
1120
1299
|
case TimeDelta():
|
|
1121
1300
|
...
|
|
1122
|
-
case
|
|
1301
|
+
case never:
|
|
1123
1302
|
assert_never(never)
|
|
1124
1303
|
py_time = draw(
|
|
1125
1304
|
hypothesis.strategies.timedeltas(
|
|
@@ -1132,6 +1311,24 @@ def time_deltas(
|
|
|
1132
1311
|
##
|
|
1133
1312
|
|
|
1134
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."""
|
|
1323
|
+
min_value_, max_value_ = [draw2(draw, v) for v in [min_value, max_value]]
|
|
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
|
+
|
|
1135
1332
|
@composite
|
|
1136
1333
|
def times(
|
|
1137
1334
|
draw: DrawFn,
|
|
@@ -1144,17 +1341,17 @@ def times(
|
|
|
1144
1341
|
min_value_, max_value_ = [draw2(draw, v) for v in [min_value, max_value]]
|
|
1145
1342
|
match min_value_:
|
|
1146
1343
|
case None:
|
|
1147
|
-
min_value_ =
|
|
1344
|
+
min_value_ = Time.MIN
|
|
1148
1345
|
case Time():
|
|
1149
1346
|
...
|
|
1150
|
-
case
|
|
1347
|
+
case never:
|
|
1151
1348
|
assert_never(never)
|
|
1152
1349
|
match max_value_:
|
|
1153
1350
|
case None:
|
|
1154
|
-
max_value_ =
|
|
1351
|
+
max_value_ = Time.MAX
|
|
1155
1352
|
case Time():
|
|
1156
1353
|
...
|
|
1157
|
-
case
|
|
1354
|
+
case never:
|
|
1158
1355
|
assert_never(never)
|
|
1159
1356
|
py_time = draw(
|
|
1160
1357
|
hypothesis.strategies.times(
|
|
@@ -1188,18 +1385,48 @@ def _triples_map[T](elements: list[T], /) -> tuple[T, T, T]:
|
|
|
1188
1385
|
##
|
|
1189
1386
|
|
|
1190
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
|
+
|
|
1191
1418
|
@composite
|
|
1192
1419
|
def uint32s(
|
|
1193
1420
|
draw: DrawFn,
|
|
1194
1421
|
/,
|
|
1195
1422
|
*,
|
|
1196
|
-
min_value: MaybeSearchStrategy[int] =
|
|
1197
|
-
max_value: MaybeSearchStrategy[int] =
|
|
1423
|
+
min_value: MaybeSearchStrategy[int | None] = None,
|
|
1424
|
+
max_value: MaybeSearchStrategy[int | None] = None,
|
|
1198
1425
|
) -> int:
|
|
1199
1426
|
"""Strategy for generating uint32s."""
|
|
1200
1427
|
min_value_, max_value_ = [draw2(draw, v) for v in [min_value, max_value]]
|
|
1201
|
-
min_value_ =
|
|
1202
|
-
max_value_ =
|
|
1428
|
+
min_value_ = max_nullable([min_value_, MIN_UINT32])
|
|
1429
|
+
max_value_ = min_nullable([max_value_, MAX_UINT32])
|
|
1203
1430
|
return draw(integers(min_value=min_value_, max_value=max_value_))
|
|
1204
1431
|
|
|
1205
1432
|
|
|
@@ -1208,19 +1435,54 @@ def uint64s(
|
|
|
1208
1435
|
draw: DrawFn,
|
|
1209
1436
|
/,
|
|
1210
1437
|
*,
|
|
1211
|
-
min_value: MaybeSearchStrategy[int] =
|
|
1212
|
-
max_value: MaybeSearchStrategy[int] =
|
|
1438
|
+
min_value: MaybeSearchStrategy[int | None] = None,
|
|
1439
|
+
max_value: MaybeSearchStrategy[int | None] = None,
|
|
1213
1440
|
) -> int:
|
|
1214
1441
|
"""Strategy for generating uint64s."""
|
|
1215
1442
|
min_value_, max_value_ = [draw2(draw, v) for v in [min_value, max_value]]
|
|
1216
|
-
min_value_ =
|
|
1217
|
-
max_value_ =
|
|
1443
|
+
min_value_ = max_nullable([min_value_, MIN_UINT64])
|
|
1444
|
+
max_value_ = min_nullable([max_value_, MAX_UINT64])
|
|
1218
1445
|
return draw(integers(min_value=min_value_, max_value=max_value_))
|
|
1219
1446
|
|
|
1220
1447
|
|
|
1221
1448
|
##
|
|
1222
1449
|
|
|
1223
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
|
+
|
|
1224
1486
|
@composite
|
|
1225
1487
|
def versions(draw: DrawFn, /, *, suffix: MaybeSearchStrategy[bool] = False) -> Version:
|
|
1226
1488
|
"""Strategy for generating versions."""
|
|
@@ -1234,7 +1496,81 @@ def versions(draw: DrawFn, /, *, suffix: MaybeSearchStrategy[bool] = False) -> V
|
|
|
1234
1496
|
|
|
1235
1497
|
|
|
1236
1498
|
@composite
|
|
1237
|
-
def
|
|
1499
|
+
def year_months(
|
|
1500
|
+
draw: DrawFn,
|
|
1501
|
+
/,
|
|
1502
|
+
*,
|
|
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()
|
|
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."""
|
|
1560
|
+
min_value_, max_value_ = [draw2(draw, v) for v in [min_value, max_value]]
|
|
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)
|
|
1567
|
+
|
|
1568
|
+
|
|
1569
|
+
##
|
|
1570
|
+
|
|
1571
|
+
|
|
1572
|
+
@composite
|
|
1573
|
+
def zoned_date_times(
|
|
1238
1574
|
draw: DrawFn,
|
|
1239
1575
|
/,
|
|
1240
1576
|
*,
|
|
@@ -1242,16 +1578,16 @@ def zoned_datetimes(
|
|
|
1242
1578
|
max_value: MaybeSearchStrategy[PlainDateTime | ZonedDateTime | None] = None,
|
|
1243
1579
|
time_zone: MaybeSearchStrategy[TimeZoneLike] = UTC,
|
|
1244
1580
|
) -> ZonedDateTime:
|
|
1245
|
-
"""Strategy for generating zoned
|
|
1581
|
+
"""Strategy for generating zoned date-times."""
|
|
1246
1582
|
min_value_, max_value_ = [draw2(draw, v) for v in [min_value, max_value]]
|
|
1247
|
-
time_zone_ =
|
|
1583
|
+
time_zone_ = to_zone_info(draw2(draw, time_zone))
|
|
1248
1584
|
match min_value_:
|
|
1249
1585
|
case None | PlainDateTime():
|
|
1250
1586
|
...
|
|
1251
1587
|
case ZonedDateTime():
|
|
1252
1588
|
with assume_does_not_raise(ValueError):
|
|
1253
1589
|
min_value_ = min_value_.to_tz(time_zone_.key).to_plain()
|
|
1254
|
-
case
|
|
1590
|
+
case never:
|
|
1255
1591
|
assert_never(never)
|
|
1256
1592
|
match max_value_:
|
|
1257
1593
|
case None | PlainDateTime():
|
|
@@ -1259,22 +1595,26 @@ def zoned_datetimes(
|
|
|
1259
1595
|
case ZonedDateTime():
|
|
1260
1596
|
with assume_does_not_raise(ValueError):
|
|
1261
1597
|
max_value_ = max_value_.to_tz(time_zone_.key).to_plain()
|
|
1262
|
-
case
|
|
1598
|
+
case never:
|
|
1263
1599
|
assert_never(never)
|
|
1264
|
-
plain = draw(
|
|
1600
|
+
plain = draw(plain_date_times(min_value=min_value_, max_value=max_value_))
|
|
1265
1601
|
with (
|
|
1266
1602
|
assume_does_not_raise(RepeatedTime),
|
|
1267
1603
|
assume_does_not_raise(SkippedTime),
|
|
1268
|
-
assume_does_not_raise(
|
|
1269
|
-
assume_does_not_raise(ValueError, match="Resulting datetime is out of range"),
|
|
1604
|
+
assume_does_not_raise(ValueError, match=r"Resulting time is out of range"),
|
|
1270
1605
|
):
|
|
1271
1606
|
zoned = plain.assume_tz(time_zone_.key, disambiguate="raise")
|
|
1272
|
-
with assume_does_not_raise(OverflowError, match="date value out of range"):
|
|
1273
|
-
if not ((
|
|
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)):
|
|
1274
1609
|
_ = zoned.py_datetime()
|
|
1275
1610
|
return zoned
|
|
1276
1611
|
|
|
1277
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
|
+
)
|
|
1617
|
+
|
|
1278
1618
|
__all__ = [
|
|
1279
1619
|
"Draw2Error",
|
|
1280
1620
|
"MaybeSearchStrategy",
|
|
@@ -1282,6 +1622,7 @@ __all__ = [
|
|
|
1282
1622
|
"assume_does_not_raise",
|
|
1283
1623
|
"bool_arrays",
|
|
1284
1624
|
"date_deltas",
|
|
1625
|
+
"date_periods",
|
|
1285
1626
|
"date_time_deltas",
|
|
1286
1627
|
"dates",
|
|
1287
1628
|
"draw2",
|
|
@@ -1289,19 +1630,24 @@ __all__ = [
|
|
|
1289
1630
|
"float64s",
|
|
1290
1631
|
"float_arrays",
|
|
1291
1632
|
"floats_extra",
|
|
1292
|
-
"freqs",
|
|
1293
1633
|
"git_repos",
|
|
1294
1634
|
"hashables",
|
|
1635
|
+
"import_froms",
|
|
1636
|
+
"imports",
|
|
1637
|
+
"int8s",
|
|
1638
|
+
"int16s",
|
|
1295
1639
|
"int32s",
|
|
1296
1640
|
"int64s",
|
|
1297
1641
|
"int_arrays",
|
|
1298
1642
|
"lists_fixed_length",
|
|
1299
|
-
"
|
|
1300
|
-
"namespace_mixins",
|
|
1643
|
+
"month_days",
|
|
1301
1644
|
"numbers",
|
|
1302
1645
|
"pairs",
|
|
1303
1646
|
"paths",
|
|
1304
|
-
"
|
|
1647
|
+
"permissions",
|
|
1648
|
+
"plain_date_times",
|
|
1649
|
+
"py_datetimes",
|
|
1650
|
+
"quadruples",
|
|
1305
1651
|
"random_states",
|
|
1306
1652
|
"sentinels",
|
|
1307
1653
|
"sets_fixed_length",
|
|
@@ -1317,10 +1663,18 @@ __all__ = [
|
|
|
1317
1663
|
"text_digits",
|
|
1318
1664
|
"text_printable",
|
|
1319
1665
|
"time_deltas",
|
|
1666
|
+
"time_periods",
|
|
1320
1667
|
"times",
|
|
1321
1668
|
"triples",
|
|
1669
|
+
"uint8s",
|
|
1670
|
+
"uint16s",
|
|
1322
1671
|
"uint32s",
|
|
1323
1672
|
"uint64s",
|
|
1673
|
+
"urls",
|
|
1324
1674
|
"versions",
|
|
1325
|
-
"
|
|
1675
|
+
"year_months",
|
|
1676
|
+
"zone_infos",
|
|
1677
|
+
"zoned_date_time_periods",
|
|
1678
|
+
"zoned_date_times",
|
|
1679
|
+
"zoned_date_times_2000",
|
|
1326
1680
|
]
|