@@ -85,20 +85,7 @@ def wrapper(tp):
85
85
return wrapper
86
86
87
87
88
- ONE_BOUND_INTEGERS_LABEL = calc_label_from_name ("trying a one-bound int allowing 0" )
89
- INTEGER_RANGE_DRAW_LABEL = calc_label_from_name ("another draw in integer_range()" )
90
- BIASED_COIN_LABEL = calc_label_from_name ("biased_coin()" )
91
-
92
88
TOP_LABEL = calc_label_from_name ("top" )
93
- DRAW_BYTES_LABEL = calc_label_from_name ("draw_bytes() in ConjectureData" )
94
- DRAW_FLOAT_LABEL = calc_label_from_name ("drawing a float" )
95
- FLOAT_STRATEGY_DO_DRAW_LABEL = calc_label_from_name (
96
- "getting another float in FloatStrategy"
97
- )
98
- INTEGER_WEIGHTED_DISTRIBUTION = calc_label_from_name (
99
- "drawing from a weighted distribution in integers"
100
- )
101
-
102
89
InterestingOrigin = Tuple [
103
90
Type [BaseException ], str , int , Tuple [Any , ...], Tuple [Tuple [Any , ...], ...]
104
91
]
@@ -370,11 +357,9 @@ def run(self) -> Any:
370
357
blocks = self .examples .blocks
371
358
for record in self .examples .trail :
372
359
if record == DRAW_BITS_RECORD :
373
- self .__push (0 )
374
360
self .bytes_read = blocks .endpoints [self .block_count ]
375
361
self .block (self .block_count )
376
362
self .block_count += 1
377
- self .__pop (discarded = False )
378
363
elif record == IR_NODE_RECORD :
379
364
data = self .examples .ir_nodes [self .ir_node_count ]
380
365
self .ir_node (data )
@@ -469,8 +454,8 @@ class ExampleRecord:
469
454
"""
470
455
471
456
def __init__ (self ) -> None :
472
- self .labels = [DRAW_BYTES_LABEL ]
473
- self .__index_of_labels : "Optional[Dict[int, int]]" = {DRAW_BYTES_LABEL : 0 }
457
+ self .labels : List [ int ] = []
458
+ self .__index_of_labels : "Optional[Dict[int, int]]" = {}
474
459
self .trail = IntList ()
475
460
self .ir_nodes : List [IRNode ] = []
476
461
@@ -522,11 +507,9 @@ def __init__(self, record: ExampleRecord, blocks: "Blocks") -> None:
522
507
self .trail = record .trail
523
508
self .ir_nodes = record .ir_nodes
524
509
self .labels = record .labels
525
- self .__length = (
526
- self .trail .count (STOP_EXAMPLE_DISCARD_RECORD )
527
- + record .trail .count (STOP_EXAMPLE_NO_DISCARD_RECORD )
528
- + record .trail .count (DRAW_BITS_RECORD )
529
- )
510
+ self .__length = self .trail .count (
511
+ STOP_EXAMPLE_DISCARD_RECORD
512
+ ) + record .trail .count (STOP_EXAMPLE_NO_DISCARD_RECORD )
530
513
self .blocks = blocks
531
514
self .__children : "Optional[List[Sequence[int]]]" = None
532
515
@@ -649,18 +632,23 @@ def start_example(self, i: int, label_index: int) -> None:
649
632
650
633
class _mutator_groups (ExampleProperty ):
651
634
def begin (self ) -> None :
652
- self .groups : "Dict[Tuple[ int, int], List[ int]]" = defaultdict (list )
635
+ self .groups : "Dict[int, Set[Tuple[ int, int]]] " = defaultdict (set )
653
636
654
637
def start_example (self , i : int , label_index : int ) -> None :
655
- depth = len (self .example_stack )
656
- self .groups [label_index , depth ].append (i )
638
+ # TODO should we discard start == end cases? occurs for eg st.data()
639
+ # which is conditionally or never drawn from. arguably swapping
640
+ # nodes with the empty list is a useful mutation enabled by start == end?
641
+ key = (self .examples [i ].ir_start , self .examples [i ].ir_end )
642
+ self .groups [label_index ].add (key )
657
643
658
- def finish (self ) -> Iterable [Iterable [ int ]]:
644
+ def finish (self ) -> Iterable [Set [ Tuple [ int , int ] ]]:
659
645
# Discard groups with only one example, since the mutator can't
660
646
# do anything useful with them.
661
647
return [g for g in self .groups .values () if len (g ) >= 2 ]
662
648
663
- mutator_groups : List [List [int ]] = calculated_example_property (_mutator_groups )
649
+ mutator_groups : List [Set [Tuple [int , int ]]] = calculated_example_property (
650
+ _mutator_groups
651
+ )
664
652
665
653
@property
666
654
def children (self ) -> List [Sequence [int ]]:
@@ -1338,7 +1326,6 @@ def draw_boolean(
1338
1326
1339
1327
size = 2 ** bits
1340
1328
1341
- self ._cd .start_example (BIASED_COIN_LABEL )
1342
1329
while True :
1343
1330
# The logic here is a bit complicated and special cased to make it
1344
1331
# play better with the shrinker.
@@ -1409,7 +1396,6 @@ def draw_boolean(
1409
1396
result = i > falsey
1410
1397
1411
1398
break
1412
- self ._cd .stop_example ()
1413
1399
return result
1414
1400
1415
1401
def draw_integer (
@@ -1460,24 +1446,20 @@ def draw_integer(
1460
1446
assert max_value is not None # make mypy happy
1461
1447
probe = max_value + 1
1462
1448
while max_value < probe :
1463
- self ._cd .start_example (ONE_BOUND_INTEGERS_LABEL )
1464
1449
probe = shrink_towards + self ._draw_unbounded_integer (
1465
1450
forced = None if forced is None else forced - shrink_towards ,
1466
1451
fake_forced = fake_forced ,
1467
1452
)
1468
- self ._cd .stop_example ()
1469
1453
return probe
1470
1454
1471
1455
if max_value is None :
1472
1456
assert min_value is not None
1473
1457
probe = min_value - 1
1474
1458
while probe < min_value :
1475
- self ._cd .start_example (ONE_BOUND_INTEGERS_LABEL )
1476
1459
probe = shrink_towards + self ._draw_unbounded_integer (
1477
1460
forced = None if forced is None else forced - shrink_towards ,
1478
1461
fake_forced = fake_forced ,
1479
1462
)
1480
- self ._cd .stop_example ()
1481
1463
return probe
1482
1464
1483
1465
return self ._draw_bounded_integer (
@@ -1518,7 +1500,6 @@ def draw_float(
1518
1500
assert self ._cd is not None
1519
1501
1520
1502
while True :
1521
- self ._cd .start_example (FLOAT_STRATEGY_DO_DRAW_LABEL )
1522
1503
# If `forced in nasty_floats`, then `forced` was *probably*
1523
1504
# generated by drawing a nonzero index from the sampler. However, we
1524
1505
# have no obligation to generate it that way when forcing. In particular,
@@ -1530,7 +1511,6 @@ def draw_float(
1530
1511
if sampler
1531
1512
else 0
1532
1513
)
1533
- self ._cd .start_example (DRAW_FLOAT_LABEL )
1534
1514
if i == 0 :
1535
1515
result = self ._draw_float (
1536
1516
forced_sign_bit = forced_sign_bit ,
@@ -1546,8 +1526,6 @@ def draw_float(
1546
1526
assert pos_clamper is not None
1547
1527
clamped = pos_clamper (result )
1548
1528
if clamped != result and not (math .isnan (result ) and allow_nan ):
1549
- self ._cd .stop_example ()
1550
- self ._cd .start_example (DRAW_FLOAT_LABEL )
1551
1529
self ._draw_float (forced = clamped , fake_forced = fake_forced )
1552
1530
result = clamped
1553
1531
else :
@@ -1576,8 +1554,6 @@ def draw_float(
1576
1554
1577
1555
self ._draw_float (forced = result , fake_forced = fake_forced )
1578
1556
1579
- self ._cd .stop_example () # (DRAW_FLOAT_LABEL)
1580
- self ._cd .stop_example () # (FLOAT_STRATEGY_DO_DRAW_LABEL)
1581
1557
return result
1582
1558
1583
1559
def draw_string (
@@ -1771,7 +1747,6 @@ def _draw_bounded_integer(
1771
1747
7 / 8 , forced = None if forced is None else False , fake_forced = fake_forced
1772
1748
)
1773
1749
):
1774
- self ._cd .start_example (INTEGER_WEIGHTED_DISTRIBUTION )
1775
1750
# For large ranges, we combine the uniform random distribution from draw_bits
1776
1751
# with a weighting scheme with moderate chance. Cutoff at 2 ** 24 so that our
1777
1752
# choice of unicode characters is uniform but the 32bit distribution is not.
@@ -1782,18 +1757,15 @@ def _draw_bounded_integer(
1782
1757
upper = center if not above else min (upper , center + 2 ** force_bits - 1 ),
1783
1758
_vary_effective_size = False ,
1784
1759
)
1785
- self ._cd .stop_example ()
1786
1760
1787
1761
assert lower <= forced <= upper
1788
1762
1789
1763
while probe > gap :
1790
- self ._cd .start_example (INTEGER_RANGE_DRAW_LABEL )
1791
1764
probe = self ._cd .draw_bits (
1792
1765
bits ,
1793
1766
forced = None if forced is None else abs (forced - center ),
1794
1767
fake_forced = fake_forced ,
1795
1768
)
1796
- self ._cd .stop_example ()
1797
1769
1798
1770
if above :
1799
1771
result = center + probe
@@ -1938,12 +1910,13 @@ def for_ir_tree(
1938
1910
* ,
1939
1911
observer : Optional [DataObserver ] = None ,
1940
1912
provider : Union [type , PrimitiveProvider ] = HypothesisProvider ,
1913
+ max_length : Optional [int ] = None ,
1941
1914
) -> "ConjectureData" :
1942
1915
from hypothesis .internal .conjecture .engine import BUFFER_SIZE
1943
1916
1944
1917
return cls (
1945
- BUFFER_SIZE ,
1946
- b"" ,
1918
+ max_length = BUFFER_SIZE if max_length is None else max_length ,
1919
+ prefix = b"" ,
1947
1920
random = None ,
1948
1921
ir_tree_prefix = ir_tree_prefix ,
1949
1922
observer = observer ,
0 commit comments