hypothesis 6.135.16__py3-none-any.whl → 6.135.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.
- hypothesis/internal/conjecture/shrinker.py +119 -209
- hypothesis/version.py +1 -1
- {hypothesis-6.135.16.dist-info → hypothesis-6.135.17.dist-info}/METADATA +1 -1
- {hypothesis-6.135.16.dist-info → hypothesis-6.135.17.dist-info}/RECORD +8 -8
- {hypothesis-6.135.16.dist-info → hypothesis-6.135.17.dist-info}/WHEEL +0 -0
- {hypothesis-6.135.16.dist-info → hypothesis-6.135.17.dist-info}/entry_points.txt +0 -0
- {hypothesis-6.135.16.dist-info → hypothesis-6.135.17.dist-info}/licenses/LICENSE.txt +0 -0
- {hypothesis-6.135.16.dist-info → hypothesis-6.135.17.dist-info}/top_level.txt +0 -0
@@ -14,8 +14,6 @@ from collections.abc import Sequence
|
|
14
14
|
from dataclasses import dataclass
|
15
15
|
from typing import TYPE_CHECKING, Any, Callable, Literal, Optional, Union, cast
|
16
16
|
|
17
|
-
import attr
|
18
|
-
|
19
17
|
from hypothesis.internal.conjecture.choice import (
|
20
18
|
ChoiceNode,
|
21
19
|
ChoiceT,
|
@@ -86,50 +84,28 @@ def sort_key(nodes: Sequence[ChoiceNode]) -> tuple[int, tuple[int, ...]]:
|
|
86
84
|
)
|
87
85
|
|
88
86
|
|
89
|
-
SHRINK_PASS_DEFINITIONS: dict[str, "ShrinkPassDefinition"] = {}
|
90
|
-
|
91
|
-
|
92
87
|
@dataclass
|
93
|
-
class
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
Each shrink pass is defined by some function and some arguments to that
|
98
|
-
function. The ``generate_arguments`` function returns all arguments that
|
99
|
-
might be useful to run on the current shrink target.
|
100
|
-
|
101
|
-
The guarantee made by methods defined this way is that after they are
|
102
|
-
called then *either* the shrink target has changed *or* each of
|
103
|
-
``fn(*args)`` has been called for every ``args`` in ``generate_arguments(self)``.
|
104
|
-
No guarantee is made that all of these will be called if the shrink target
|
105
|
-
changes.
|
106
|
-
"""
|
107
|
-
|
108
|
-
run_with_chooser: Any
|
109
|
-
|
110
|
-
@property
|
111
|
-
def name(self) -> str:
|
112
|
-
return self.run_with_chooser.__name__
|
113
|
-
|
114
|
-
def __post_init__(self) -> None:
|
115
|
-
assert self.name not in SHRINK_PASS_DEFINITIONS, self.name
|
116
|
-
SHRINK_PASS_DEFINITIONS[self.name] = self
|
117
|
-
|
88
|
+
class ShrinkPass:
|
89
|
+
function: Any
|
90
|
+
name: Optional[str] = None
|
91
|
+
last_prefix: Any = ()
|
118
92
|
|
119
|
-
|
120
|
-
|
93
|
+
# some execution statistics
|
94
|
+
calls: int = 0
|
95
|
+
misaligned: int = 0
|
96
|
+
shrinks: int = 0
|
97
|
+
deletions: int = 0
|
121
98
|
|
122
|
-
def
|
123
|
-
|
99
|
+
def __post_init__(self):
|
100
|
+
if self.name is None:
|
101
|
+
self.name = self.function.__name__
|
124
102
|
|
125
|
-
|
126
|
-
|
103
|
+
def __hash__(self):
|
104
|
+
return hash(self.name)
|
127
105
|
|
128
|
-
run.__name__ = run_step.__name__
|
129
|
-
run.is_shrink_pass = True
|
130
|
-
return run
|
131
106
|
|
132
|
-
|
107
|
+
class StopShrinking(Exception):
|
108
|
+
pass
|
133
109
|
|
134
110
|
|
135
111
|
class Shrinker:
|
@@ -326,7 +302,21 @@ class Shrinker:
|
|
326
302
|
self.initial_misaligned = self.engine.misaligned_count
|
327
303
|
self.calls_at_last_shrink = self.initial_calls
|
328
304
|
|
329
|
-
self.
|
305
|
+
self.shrink_passes: list[ShrinkPass] = [
|
306
|
+
ShrinkPass(self.try_trivial_spans),
|
307
|
+
self.node_program("X" * 5),
|
308
|
+
self.node_program("X" * 4),
|
309
|
+
self.node_program("X" * 3),
|
310
|
+
self.node_program("X" * 2),
|
311
|
+
self.node_program("X" * 1),
|
312
|
+
ShrinkPass(self.pass_to_descendant),
|
313
|
+
ShrinkPass(self.reorder_spans),
|
314
|
+
ShrinkPass(self.minimize_duplicated_choices),
|
315
|
+
ShrinkPass(self.minimize_individual_choices),
|
316
|
+
ShrinkPass(self.redistribute_numeric_pairs),
|
317
|
+
ShrinkPass(self.lower_integers_together),
|
318
|
+
ShrinkPass(self.lower_duplicated_characters),
|
319
|
+
]
|
330
320
|
|
331
321
|
# Because the shrinker is also used to `pareto_optimise` in the target phase,
|
332
322
|
# we sometimes want to allow extending buffers instead of aborting at the end.
|
@@ -347,27 +337,6 @@ class Shrinker:
|
|
347
337
|
|
348
338
|
return accept
|
349
339
|
|
350
|
-
def add_new_pass(self, run):
|
351
|
-
"""Creates a shrink pass corresponding to calling ``run(self)``"""
|
352
|
-
|
353
|
-
definition = SHRINK_PASS_DEFINITIONS[run]
|
354
|
-
|
355
|
-
p = ShrinkPass(
|
356
|
-
run_with_chooser=definition.run_with_chooser,
|
357
|
-
shrinker=self,
|
358
|
-
index=len(self.passes_by_name),
|
359
|
-
)
|
360
|
-
self.passes_by_name[p.name] = p
|
361
|
-
return p
|
362
|
-
|
363
|
-
def shrink_pass(self, name):
|
364
|
-
"""Return the ShrinkPass object for the pass with the given name."""
|
365
|
-
if isinstance(name, ShrinkPass):
|
366
|
-
return name
|
367
|
-
if name not in self.passes_by_name:
|
368
|
-
self.add_new_pass(name)
|
369
|
-
return self.passes_by_name[name]
|
370
|
-
|
371
340
|
@property
|
372
341
|
def calls(self) -> int:
|
373
342
|
"""Return the number of calls that have been made to the underlying
|
@@ -467,19 +436,19 @@ class Shrinker:
|
|
467
436
|
else:
|
468
437
|
self.debug("Useless passes:")
|
469
438
|
self.debug("")
|
470
|
-
for
|
471
|
-
self.
|
439
|
+
for pass_ in sorted(
|
440
|
+
self.shrink_passes,
|
472
441
|
key=lambda t: (-t.calls, t.deletions, t.shrinks),
|
473
442
|
):
|
474
|
-
if
|
443
|
+
if pass_.calls == 0:
|
475
444
|
continue
|
476
|
-
if (
|
445
|
+
if (pass_.shrinks != 0) != useful:
|
477
446
|
continue
|
478
447
|
|
479
448
|
self.debug(
|
480
|
-
f" * {
|
481
|
-
f"{
|
482
|
-
f"deleting {
|
449
|
+
f" * {pass_.name} made {pass_.calls} call{s(pass_.calls)} of which "
|
450
|
+
f"{pass_.shrinks} shrank and {pass_.misaligned} were misaligned, "
|
451
|
+
f"deleting {pass_.deletions} choice{s(pass_.deletions)}."
|
483
452
|
)
|
484
453
|
self.debug("")
|
485
454
|
self.explain()
|
@@ -628,23 +597,7 @@ class Shrinker:
|
|
628
597
|
This method iterates to a fixed point and so is idempontent - calling
|
629
598
|
it twice will have exactly the same effect as calling it once.
|
630
599
|
"""
|
631
|
-
self.fixate_shrink_passes(
|
632
|
-
[
|
633
|
-
"try_trivial_spans",
|
634
|
-
node_program("X" * 5),
|
635
|
-
node_program("X" * 4),
|
636
|
-
node_program("X" * 3),
|
637
|
-
node_program("X" * 2),
|
638
|
-
node_program("X" * 1),
|
639
|
-
"pass_to_descendant",
|
640
|
-
"reorder_spans",
|
641
|
-
"minimize_duplicated_choices",
|
642
|
-
"minimize_individual_choices",
|
643
|
-
"redistribute_numeric_pairs",
|
644
|
-
"lower_integers_together",
|
645
|
-
"lower_duplicated_characters",
|
646
|
-
]
|
647
|
-
)
|
600
|
+
self.fixate_shrink_passes(self.shrink_passes)
|
648
601
|
|
649
602
|
def initial_coarse_reduction(self):
|
650
603
|
"""Performs some preliminary reductions that should not be
|
@@ -759,14 +712,42 @@ class Shrinker:
|
|
759
712
|
return False
|
760
713
|
|
761
714
|
@derived_value # type: ignore
|
762
|
-
def shrink_pass_choice_trees(self):
|
715
|
+
def shrink_pass_choice_trees(self) -> dict[Any, ChoiceTree]:
|
763
716
|
return defaultdict(ChoiceTree)
|
764
717
|
|
765
|
-
def
|
718
|
+
def step(self, shrink_pass: ShrinkPass, *, random_order: bool = False) -> bool:
|
719
|
+
tree = self.shrink_pass_choice_trees[shrink_pass]
|
720
|
+
if tree.exhausted:
|
721
|
+
return False
|
722
|
+
|
723
|
+
initial_shrinks = self.shrinks
|
724
|
+
initial_calls = self.calls
|
725
|
+
initial_misaligned = self.misaligned
|
726
|
+
size = len(self.shrink_target.choices)
|
727
|
+
assert shrink_pass.name is not None
|
728
|
+
self.engine.explain_next_call_as(shrink_pass.name)
|
729
|
+
|
730
|
+
if random_order:
|
731
|
+
selection_order = random_selection_order(self.random)
|
732
|
+
else:
|
733
|
+
selection_order = prefix_selection_order(shrink_pass.last_prefix)
|
734
|
+
|
735
|
+
try:
|
736
|
+
shrink_pass.last_prefix = tree.step(
|
737
|
+
selection_order,
|
738
|
+
lambda chooser: shrink_pass.function(chooser),
|
739
|
+
)
|
740
|
+
finally:
|
741
|
+
shrink_pass.calls += self.calls - initial_calls
|
742
|
+
shrink_pass.misaligned += self.misaligned - initial_misaligned
|
743
|
+
shrink_pass.shrinks += self.shrinks - initial_shrinks
|
744
|
+
shrink_pass.deletions += size - len(self.shrink_target.choices)
|
745
|
+
self.engine.clear_call_explanation()
|
746
|
+
return True
|
747
|
+
|
748
|
+
def fixate_shrink_passes(self, passes: list[ShrinkPass]) -> None:
|
766
749
|
"""Run steps from each pass in ``passes`` until the current shrink target
|
767
750
|
is a fixed point of all of them."""
|
768
|
-
passes = list(map(self.shrink_pass, passes))
|
769
|
-
|
770
751
|
any_ran = True
|
771
752
|
while any_ran:
|
772
753
|
any_ran = False
|
@@ -824,7 +805,7 @@ class Shrinker:
|
|
824
805
|
# to do anything) we switch to randomly jumping around. If we
|
825
806
|
# find a success then we'll resume deterministic order from
|
826
807
|
# there which, with any luck, is in a new good region.
|
827
|
-
if not
|
808
|
+
if not self.step(sp, random_order=failures >= max_failures // 2):
|
828
809
|
# step returns False when there is nothing to do because
|
829
810
|
# the entire choice tree is exhausted. If this happens
|
830
811
|
# we break because we literally can't run this pass any
|
@@ -886,7 +867,6 @@ class Shrinker:
|
|
886
867
|
def distinct_labels(self):
|
887
868
|
return sorted(self.spans_by_label, key=str)
|
888
869
|
|
889
|
-
@defines_shrink_pass()
|
890
870
|
def pass_to_descendant(self, chooser):
|
891
871
|
"""Attempt to replace each span with a descendant span.
|
892
872
|
|
@@ -964,13 +944,13 @@ class Shrinker:
|
|
964
944
|
sequence: The number of iterations that reduce the length of the choice
|
965
945
|
sequence is bounded by that length.
|
966
946
|
|
967
|
-
So what we do is this: We keep track of which
|
947
|
+
So what we do is this: We keep track of which nodes are changing, and
|
968
948
|
then if there's some non-zero common offset to them we try and minimize
|
969
949
|
them all at once by lowering that offset.
|
970
950
|
|
971
951
|
This may not work, and it definitely won't get us out of all possible
|
972
952
|
exponential slow downs (an example of where it doesn't is where the
|
973
|
-
shape of the
|
953
|
+
shape of the nodes changes as a result of this bouncing behaviour),
|
974
954
|
but it fails fast when it doesn't work and gets us out of a really
|
975
955
|
nastily slow case when it does.
|
976
956
|
"""
|
@@ -1177,7 +1157,7 @@ class Shrinker:
|
|
1177
1157
|
# We now look for contiguous regions to delete that might help fix up
|
1178
1158
|
# this failed shrink. We only look for contiguous regions of the right
|
1179
1159
|
# lengths because doing anything more than that starts to get very
|
1180
|
-
# expensive. See
|
1160
|
+
# expensive. See minimize_individual_choices for where we
|
1181
1161
|
# try to be more aggressive.
|
1182
1162
|
regions_to_delete = {(end, end + lost_nodes)}
|
1183
1163
|
|
@@ -1264,7 +1244,45 @@ class Shrinker:
|
|
1264
1244
|
duplicates[(node.type, choice_key(node.value))].append(node)
|
1265
1245
|
return list(duplicates.values())
|
1266
1246
|
|
1267
|
-
|
1247
|
+
def node_program(self, program: str) -> ShrinkPass:
|
1248
|
+
return ShrinkPass(
|
1249
|
+
lambda chooser: self._node_program(chooser, program),
|
1250
|
+
name=f"node_program_{program}",
|
1251
|
+
)
|
1252
|
+
|
1253
|
+
def _node_program(self, chooser, program):
|
1254
|
+
n = len(program)
|
1255
|
+
# Adaptively attempt to run the node program at the current
|
1256
|
+
# index. If this successfully applies the node program ``k`` times
|
1257
|
+
# then this runs in ``O(log(k))`` test function calls.
|
1258
|
+
i = chooser.choose(range(len(self.nodes) - n + 1))
|
1259
|
+
|
1260
|
+
# First, run the node program at the chosen index. If this fails,
|
1261
|
+
# don't do any extra work, so that failure is as cheap as possible.
|
1262
|
+
if not self.run_node_program(i, program, original=self.shrink_target):
|
1263
|
+
return
|
1264
|
+
|
1265
|
+
# Because we run in a random order we will often find ourselves in the middle
|
1266
|
+
# of a region where we could run the node program. We thus start by moving
|
1267
|
+
# left to the beginning of that region if possible in order to to start from
|
1268
|
+
# the beginning of that region.
|
1269
|
+
def offset_left(k):
|
1270
|
+
return i - k * n
|
1271
|
+
|
1272
|
+
i = offset_left(
|
1273
|
+
find_integer(
|
1274
|
+
lambda k: self.run_node_program(
|
1275
|
+
offset_left(k), program, original=self.shrink_target
|
1276
|
+
)
|
1277
|
+
)
|
1278
|
+
)
|
1279
|
+
|
1280
|
+
original = self.shrink_target
|
1281
|
+
# Now try to run the node program multiple times here.
|
1282
|
+
find_integer(
|
1283
|
+
lambda k: self.run_node_program(i, program, original=original, repeats=k)
|
1284
|
+
)
|
1285
|
+
|
1268
1286
|
def minimize_duplicated_choices(self, chooser):
|
1269
1287
|
"""Find choices that have been duplicated in multiple places and attempt
|
1270
1288
|
to minimize all of the duplicates simultaneously.
|
@@ -1282,7 +1300,7 @@ class Shrinker:
|
|
1282
1300
|
to replace either 3 with 0 on its own the test would start passing.
|
1283
1301
|
|
1284
1302
|
It is also useful for when that duplication is accidental and the value
|
1285
|
-
of the
|
1303
|
+
of the choices don't matter very much because it allows us to replace
|
1286
1304
|
more values at once.
|
1287
1305
|
"""
|
1288
1306
|
nodes = chooser.choose(self.duplicated_nodes)
|
@@ -1294,7 +1312,6 @@ class Shrinker:
|
|
1294
1312
|
|
1295
1313
|
self.minimize_nodes(nodes)
|
1296
1314
|
|
1297
|
-
@defines_shrink_pass()
|
1298
1315
|
def redistribute_numeric_pairs(self, chooser):
|
1299
1316
|
"""If there is a sum of generated numbers that we need their sum
|
1300
1317
|
to exceed some bound, lowering one of them requires raising the
|
@@ -1360,7 +1377,6 @@ class Shrinker:
|
|
1360
1377
|
|
1361
1378
|
find_integer(boost)
|
1362
1379
|
|
1363
|
-
@defines_shrink_pass()
|
1364
1380
|
def lower_integers_together(self, chooser):
|
1365
1381
|
node1 = chooser.choose(
|
1366
1382
|
self.nodes, lambda n: n.type == "integer" and not n.trivial
|
@@ -1393,7 +1409,6 @@ class Shrinker:
|
|
1393
1409
|
find_integer(lambda n: consider(shrink_towards - n))
|
1394
1410
|
find_integer(lambda n: consider(n - shrink_towards))
|
1395
1411
|
|
1396
|
-
@defines_shrink_pass()
|
1397
1412
|
def lower_duplicated_characters(self, chooser):
|
1398
1413
|
"""
|
1399
1414
|
Select two string choices no more than 4 choices apart and simultaneously
|
@@ -1516,7 +1531,6 @@ class Shrinker:
|
|
1516
1531
|
else:
|
1517
1532
|
raise NotImplementedError
|
1518
1533
|
|
1519
|
-
@defines_shrink_pass()
|
1520
1534
|
def try_trivial_spans(self, chooser):
|
1521
1535
|
i = chooser.choose(range(len(self.spans)))
|
1522
1536
|
|
@@ -1547,7 +1561,6 @@ class Shrinker:
|
|
1547
1561
|
new_replacement = attempt.nodes[new_ex.start : new_ex.end]
|
1548
1562
|
self.consider_new_nodes(prefix + new_replacement + suffix)
|
1549
1563
|
|
1550
|
-
@defines_shrink_pass()
|
1551
1564
|
def minimize_individual_choices(self, chooser):
|
1552
1565
|
"""Attempt to minimize each choice in sequence.
|
1553
1566
|
|
@@ -1648,7 +1661,6 @@ class Shrinker:
|
|
1648
1661
|
node = self.nodes[chooser.choose(range(node.index + 1, len(self.nodes)))]
|
1649
1662
|
self.consider_new_nodes(lowered[: node.index] + lowered[node.index + 1 :])
|
1650
1663
|
|
1651
|
-
@defines_shrink_pass()
|
1652
1664
|
def reorder_spans(self, chooser):
|
1653
1665
|
"""This pass allows us to reorder the children of each span.
|
1654
1666
|
|
@@ -1695,7 +1707,7 @@ class Shrinker:
|
|
1695
1707
|
key=lambda i: sort_key(st.nodes[spans[i].start : spans[i].end]),
|
1696
1708
|
)
|
1697
1709
|
|
1698
|
-
def run_node_program(self, i,
|
1710
|
+
def run_node_program(self, i, program, original, repeats=1):
|
1699
1711
|
"""Node programs are a mini-DSL for node rewriting, defined as a sequence
|
1700
1712
|
of commands that can be run at some index into the nodes
|
1701
1713
|
|
@@ -1703,18 +1715,18 @@ class Shrinker:
|
|
1703
1715
|
|
1704
1716
|
* "X", delete this node
|
1705
1717
|
|
1706
|
-
This method runs the node program in ``
|
1718
|
+
This method runs the node program in ``program`` at node index
|
1707
1719
|
``i`` on the ConjectureData ``original``. If ``repeats > 1`` then it
|
1708
1720
|
will attempt to approximate the results of running it that many times.
|
1709
1721
|
|
1710
1722
|
Returns True if this successfully changes the underlying shrink target,
|
1711
1723
|
else False.
|
1712
1724
|
"""
|
1713
|
-
if i + len(
|
1725
|
+
if i + len(program) > len(original.nodes) or i < 0:
|
1714
1726
|
return False
|
1715
1727
|
attempt = list(original.nodes)
|
1716
1728
|
for _ in range(repeats):
|
1717
|
-
for k, command in reversed(list(enumerate(
|
1729
|
+
for k, command in reversed(list(enumerate(program))):
|
1718
1730
|
j = i + k
|
1719
1731
|
if j >= len(attempt):
|
1720
1732
|
return False
|
@@ -1725,105 +1737,3 @@ class Shrinker:
|
|
1725
1737
|
raise NotImplementedError(f"Unrecognised command {command!r}")
|
1726
1738
|
|
1727
1739
|
return self.consider_new_nodes(attempt)
|
1728
|
-
|
1729
|
-
|
1730
|
-
def shrink_pass_family(f):
|
1731
|
-
def accept(*args):
|
1732
|
-
name = "{}({})".format(f.__name__, ", ".join(map(repr, args)))
|
1733
|
-
if name not in SHRINK_PASS_DEFINITIONS:
|
1734
|
-
|
1735
|
-
def run(self, chooser):
|
1736
|
-
return f(self, chooser, *args)
|
1737
|
-
|
1738
|
-
run.__name__ = name
|
1739
|
-
defines_shrink_pass()(run)
|
1740
|
-
assert name in SHRINK_PASS_DEFINITIONS
|
1741
|
-
return name
|
1742
|
-
|
1743
|
-
return accept
|
1744
|
-
|
1745
|
-
|
1746
|
-
@shrink_pass_family
|
1747
|
-
def node_program(self, chooser, description):
|
1748
|
-
n = len(description)
|
1749
|
-
# Adaptively attempt to run the node program at the current
|
1750
|
-
# index. If this successfully applies the node program ``k`` times
|
1751
|
-
# then this runs in ``O(log(k))`` test function calls.
|
1752
|
-
i = chooser.choose(range(len(self.nodes) - n + 1))
|
1753
|
-
|
1754
|
-
# First, run the node program at the chosen index. If this fails,
|
1755
|
-
# don't do any extra work, so that failure is as cheap as possible.
|
1756
|
-
if not self.run_node_program(i, description, original=self.shrink_target):
|
1757
|
-
return
|
1758
|
-
|
1759
|
-
# Because we run in a random order we will often find ourselves in the middle
|
1760
|
-
# of a region where we could run the node program. We thus start by moving
|
1761
|
-
# left to the beginning of that region if possible in order to to start from
|
1762
|
-
# the beginning of that region.
|
1763
|
-
def offset_left(k):
|
1764
|
-
return i - k * n
|
1765
|
-
|
1766
|
-
i = offset_left(
|
1767
|
-
find_integer(
|
1768
|
-
lambda k: self.run_node_program(
|
1769
|
-
offset_left(k), description, original=self.shrink_target
|
1770
|
-
)
|
1771
|
-
)
|
1772
|
-
)
|
1773
|
-
|
1774
|
-
original = self.shrink_target
|
1775
|
-
# Now try to run the block program multiple times here.
|
1776
|
-
find_integer(
|
1777
|
-
lambda k: self.run_node_program(i, description, original=original, repeats=k)
|
1778
|
-
)
|
1779
|
-
|
1780
|
-
|
1781
|
-
@attr.s(slots=True, eq=False)
|
1782
|
-
class ShrinkPass:
|
1783
|
-
run_with_chooser = attr.ib()
|
1784
|
-
index = attr.ib()
|
1785
|
-
shrinker = attr.ib()
|
1786
|
-
|
1787
|
-
last_prefix = attr.ib(default=())
|
1788
|
-
successes = attr.ib(default=0)
|
1789
|
-
calls = attr.ib(default=0)
|
1790
|
-
misaligned = attr.ib(default=0)
|
1791
|
-
shrinks = attr.ib(default=0)
|
1792
|
-
deletions = attr.ib(default=0)
|
1793
|
-
|
1794
|
-
def step(self, *, random_order=False):
|
1795
|
-
tree = self.shrinker.shrink_pass_choice_trees[self]
|
1796
|
-
if tree.exhausted:
|
1797
|
-
return False
|
1798
|
-
|
1799
|
-
initial_shrinks = self.shrinker.shrinks
|
1800
|
-
initial_calls = self.shrinker.calls
|
1801
|
-
initial_misaligned = self.shrinker.misaligned
|
1802
|
-
size = len(self.shrinker.shrink_target.choices)
|
1803
|
-
self.shrinker.engine.explain_next_call_as(self.name)
|
1804
|
-
|
1805
|
-
if random_order:
|
1806
|
-
selection_order = random_selection_order(self.shrinker.random)
|
1807
|
-
else:
|
1808
|
-
selection_order = prefix_selection_order(self.last_prefix)
|
1809
|
-
|
1810
|
-
try:
|
1811
|
-
self.last_prefix = tree.step(
|
1812
|
-
selection_order,
|
1813
|
-
lambda chooser: self.run_with_chooser(self.shrinker, chooser),
|
1814
|
-
)
|
1815
|
-
finally:
|
1816
|
-
self.calls += self.shrinker.calls - initial_calls
|
1817
|
-
self.misaligned += self.shrinker.misaligned - initial_misaligned
|
1818
|
-
self.shrinks += self.shrinker.shrinks - initial_shrinks
|
1819
|
-
self.deletions += size - len(self.shrinker.shrink_target.choices)
|
1820
|
-
self.shrinker.engine.clear_call_explanation()
|
1821
|
-
return True
|
1822
|
-
|
1823
|
-
@property
|
1824
|
-
def name(self) -> str:
|
1825
|
-
return self.run_with_chooser.__name__
|
1826
|
-
|
1827
|
-
|
1828
|
-
class StopShrinking(Exception):
|
1829
|
-
pass
|
hypothesis/version.py
CHANGED
@@ -14,7 +14,7 @@ hypothesis/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
14
14
|
hypothesis/reporting.py,sha256=f-jhl1JfAi5_tG8dsUd2qDjGcPdvxEzfF6hXmpTFQ1g,1761
|
15
15
|
hypothesis/stateful.py,sha256=33U0FtVuRnY5EzIiCL50SHAT6ZPe1n2pbaohkxTF6gc,42955
|
16
16
|
hypothesis/statistics.py,sha256=kZ5mc0fAg7gnSO6EmDo82fyz8DYhIiJ_mHe7srxOeQ0,5438
|
17
|
-
hypothesis/version.py,sha256=
|
17
|
+
hypothesis/version.py,sha256=MatNJOo93xvc_T0nUt6o1xfqnrZ6_26sZzWD3kCE0x0,499
|
18
18
|
hypothesis/extra/__init__.py,sha256=gx4ENVDkrzBxy5Lv3Iyfs3tvMGdWMbiHfi95B7t61CY,415
|
19
19
|
hypothesis/extra/_array_helpers.py,sha256=PLmFckBfQpzQ4Q3dFJQqMmrbm7Qdvqxf1t9LHDCuSp0,27627
|
20
20
|
hypothesis/extra/_patching.py,sha256=A5s5EAf81itr--w4SAFyzuecSZm4eT397jM7BvbnQXU,12385
|
@@ -63,7 +63,7 @@ hypothesis/internal/conjecture/optimiser.py,sha256=DI_1IZ3ncmqGYkxzldSTFWqMpLND8
|
|
63
63
|
hypothesis/internal/conjecture/pareto.py,sha256=WPWvMOFR5HDNZsIoBrWkdNQoRfKdemL5kld2LkzRkfY,15347
|
64
64
|
hypothesis/internal/conjecture/provider_conformance.py,sha256=uj5qJzf1rorX-2SZJ9tZluT1HY3LwZEo8RDXqwEP-XI,16329
|
65
65
|
hypothesis/internal/conjecture/providers.py,sha256=npX6jUNiOsFe0Q6HCwGcNNMCufq6coQi0hBfUO8e1Fo,42642
|
66
|
-
hypothesis/internal/conjecture/shrinker.py,sha256=
|
66
|
+
hypothesis/internal/conjecture/shrinker.py,sha256=vf8nH_uLTYkmnJwdiqWxjZuS1rEfMA0W8uBonPpKAFo,73088
|
67
67
|
hypothesis/internal/conjecture/utils.py,sha256=hQNW_50qTPsqJjdSA7rvqBG2SfDQ0rsJJtnKNYXvBX0,13694
|
68
68
|
hypothesis/internal/conjecture/dfa/__init__.py,sha256=s6RdUNlNd9EiTowj5PFDxPEOjsDw3xemp_c7Y_vjzq0,23904
|
69
69
|
hypothesis/internal/conjecture/dfa/lstar.py,sha256=SQykZRn73Yi0WPHC_maYvHrklXkBzn1pmg8hk4i18LY,19317
|
@@ -105,9 +105,9 @@ hypothesis/utils/terminal.py,sha256=IxGYDGaE4R3b_vMfz5buWbN18XH5qVP4IxqAgNAU5as,
|
|
105
105
|
hypothesis/vendor/__init__.py,sha256=gx4ENVDkrzBxy5Lv3Iyfs3tvMGdWMbiHfi95B7t61CY,415
|
106
106
|
hypothesis/vendor/pretty.py,sha256=WEZC-UV-QQgCjUf2Iz1WWaWnbgT7Hc3s-GWEVxq-Qz0,36114
|
107
107
|
hypothesis/vendor/tlds-alpha-by-domain.txt,sha256=W9hYvpu2BMmNgE-SfPp8-GTzEVjw0HJUviqlvHwpZu8,9588
|
108
|
-
hypothesis-6.135.
|
109
|
-
hypothesis-6.135.
|
110
|
-
hypothesis-6.135.
|
111
|
-
hypothesis-6.135.
|
112
|
-
hypothesis-6.135.
|
113
|
-
hypothesis-6.135.
|
108
|
+
hypothesis-6.135.17.dist-info/licenses/LICENSE.txt,sha256=rIkDe6xjVQZE3OjPMsZ2Xl-rncGhzpS4n4qAXzQaZ1A,17141
|
109
|
+
hypothesis-6.135.17.dist-info/METADATA,sha256=6zaC1bIoiwHzPdxsRo5v7cjRKrh8hkcZ-qkicY0BeBA,5638
|
110
|
+
hypothesis-6.135.17.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
111
|
+
hypothesis-6.135.17.dist-info/entry_points.txt,sha256=JDoUs9w1bYme7aG_eJ1cCtstRTWD71BzG8iRi-G2eHE,113
|
112
|
+
hypothesis-6.135.17.dist-info/top_level.txt,sha256=ReGreaueiJ4d1I2kEiig_CLeA0sD4QCQ4qk_8kH1oDc,81
|
113
|
+
hypothesis-6.135.17.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|