22
22
import hypothesis .internal .conjecture .utils as cu
23
23
from hypothesis .errors import NoExamples , NoSuchExample , Unsatisfiable , \
24
24
UnsatisfiedAssumption
25
- from hypothesis .control import assume , reject , _current_build_context
25
+ from hypothesis .control import assume , _current_build_context
26
26
from hypothesis ._settings import note_deprecation
27
27
from hypothesis .internal .compat import hrange , bit_length
28
28
from hypothesis .utils .conventions import UniqueIdentifier
31
31
from hypothesis .internal .conjecture .utils import LABEL_MASK , \
32
32
combine_labels , calc_label_from_cls , calc_label_from_name
33
33
34
+ try :
35
+ from random import Random # noqa
36
+ from typing import List , Callable , TypeVar , Generic , Optional # noqa
37
+ Ex = TypeVar ('Ex' , covariant = True )
38
+ T = TypeVar ('T' )
39
+
40
+ from hypothesis .internal .conjecture .data import ConjectureData # noqa
41
+
42
+ except ImportError : # pragma: no cover
43
+ Ex = 'key' # type: ignore
44
+ Generic = {Ex : object } # type: ignore
45
+
34
46
calculating = UniqueIdentifier ('calculating' )
35
47
36
48
MAPPED_SEARCH_STRATEGY_DO_DRAW_LABEL = calc_label_from_name (
@@ -45,7 +57,7 @@ def one_of_strategies(xs):
45
57
return OneOfStrategy (xs )
46
58
47
59
48
- class SearchStrategy (object ):
60
+ class SearchStrategy (Generic [ Ex ] ):
49
61
"""A SearchStrategy is an object that knows how to explore data of a given
50
62
type.
51
63
@@ -228,6 +240,7 @@ def calc_has_reusable_values(self, recur):
228
240
return False
229
241
230
242
def example (self , random = None ):
243
+ # type: (Random) -> Ex
231
244
"""Provide an example of the sort of value that this strategy
232
245
generates. This is biased to be slightly simpler than is typical for
233
246
values from this strategy, for clarity purposes.
@@ -270,7 +283,7 @@ def example(self, random=None):
270
283
# Conjecture will always try the zero example first. This would result
271
284
# in us producing the same example each time, which is boring, so we
272
285
# deliberately skip the first example it feeds us.
273
- first = []
286
+ first = [] # type: list
274
287
275
288
def condition (x ):
276
289
if first :
@@ -299,6 +312,7 @@ def condition(x):
299
312
)
300
313
301
314
def map (self , pack ):
315
+ # type: (Callable[[Ex], T]) -> SearchStrategy[T]
302
316
"""Returns a new strategy that generates values by generating a value
303
317
from this strategy and then calling pack() on the result, giving that.
304
318
@@ -309,6 +323,7 @@ def map(self, pack):
309
323
)
310
324
311
325
def flatmap (self , expand ):
326
+ # type: (Callable[[Ex], SearchStrategy[T]]) -> SearchStrategy[T]
312
327
"""Returns a new strategy that generates values by generating a value
313
328
from this strategy, say x, then generating a value from
314
329
strategy(expand(x))
@@ -321,6 +336,7 @@ def flatmap(self, expand):
321
336
)
322
337
323
338
def filter (self , condition ):
339
+ # type: (Callable[[Ex], bool]) -> SearchStrategy[Ex]
324
340
"""Returns a new strategy that generates values from this strategy
325
341
which satisfy the provided condition. Note that if the condition is too
326
342
hard to satisfy this might result in your tests failing with
@@ -335,6 +351,7 @@ def filter(self, condition):
335
351
336
352
@property
337
353
def branches (self ):
354
+ # type: () -> List[SearchStrategy[Ex]]
338
355
return [self ]
339
356
340
357
def __or__ (self , other ):
@@ -348,6 +365,7 @@ def __or__(self, other):
348
365
return one_of_strategies ((self , other ))
349
366
350
367
def validate (self ):
368
+ # type: () -> None
351
369
"""Throw an exception if the strategy is not valid.
352
370
353
371
This can happen due to lazy construction
@@ -392,6 +410,7 @@ def do_validate(self):
392
410
pass
393
411
394
412
def do_draw (self , data ):
413
+ # type: (ConjectureData) -> Ex
395
414
raise NotImplementedError ('%s.do_draw' % (type (self ).__name__ ,))
396
415
397
416
def __init__ (self ):
@@ -469,6 +488,7 @@ def calc_label(self):
469
488
])
470
489
471
490
def do_draw (self , data ):
491
+ # type: (ConjectureData) -> Ex
472
492
n = len (self .element_strategies )
473
493
assert n > 0
474
494
if n == 1 :
@@ -538,6 +558,7 @@ def pack(self, x): # type: ignore
538
558
'%s.pack()' % (self .__class__ .__name__ ))
539
559
540
560
def do_draw (self , data ):
561
+ # type: (ConjectureData) -> Ex
541
562
for _ in range (3 ):
542
563
i = data .index
543
564
try :
@@ -549,10 +570,11 @@ def do_draw(self, data):
549
570
data .stop_example (discard = True )
550
571
if data .index == i :
551
572
raise
552
- reject ()
573
+ raise UnsatisfiedAssumption ()
553
574
554
575
@property
555
576
def branches (self ):
577
+ # type: () -> List[SearchStrategy[Ex]]
556
578
return [
557
579
MappedSearchStrategy (pack = self .pack , strategy = strategy )
558
580
for strategy in self .mapped_strategy .branches
@@ -584,6 +606,7 @@ def do_validate(self):
584
606
self .filtered_strategy .validate ()
585
607
586
608
def do_draw (self , data ):
609
+ # type: (ConjectureData) -> Ex
587
610
for i in hrange (3 ):
588
611
start_index = data .index
589
612
value = data .draw (self .filtered_strategy )
@@ -601,9 +624,11 @@ def do_draw(self, data):
601
624
self ,
602
625
))
603
626
data .mark_invalid ()
627
+ raise AssertionError ('Unreachable, for Mypy' ) # pragma: no cover
604
628
605
629
@property
606
630
def branches (self ):
631
+ # type: () -> List[SearchStrategy[Ex]]
607
632
return [
608
633
FilteredStrategy (strategy = strategy , condition = self .condition )
609
634
for strategy in self .filtered_strategy .branches
0 commit comments