8
8
# v. 2.0. If a copy of the MPL was not distributed with this file, You can
9
9
# obtain one at https://mozilla.org/MPL/2.0/.
10
10
11
+ from collections .abc import Iterator
11
12
from enum import Enum
13
+ from random import Random
14
+ from typing import TYPE_CHECKING , Callable , Optional , Union , cast
12
15
13
16
from sortedcontainers import SortedList
14
17
15
18
from hypothesis .internal .conjecture .choice import choices_key
16
- from hypothesis .internal .conjecture .data import ConjectureData , ConjectureResult , Status
19
+ from hypothesis .internal .conjecture .data import (
20
+ ConjectureData ,
21
+ ConjectureResult ,
22
+ Status ,
23
+ _Overrun ,
24
+ )
17
25
from hypothesis .internal .conjecture .junkdrawer import LazySequenceCopy
18
26
from hypothesis .internal .conjecture .shrinker import sort_key
19
27
20
28
NO_SCORE = float ("-inf" )
21
29
30
+ if TYPE_CHECKING :
31
+ from hypothesis .internal .conjecture .engine import ConjectureRunner
32
+
22
33
23
34
class DominanceRelation (Enum ):
24
35
NO_DOMINANCE = 0
@@ -27,7 +38,7 @@ class DominanceRelation(Enum):
27
38
RIGHT_DOMINATES = 3
28
39
29
40
30
- def dominance (left , right ) :
41
+ def dominance (left : ConjectureResult , right : ConjectureResult ) -> DominanceRelation :
31
42
"""Returns the dominance relation between ``left`` and ``right``, according
32
43
to the rules that one ConjectureResult dominates another if and only if it
33
44
is better in every way.
@@ -125,21 +136,25 @@ class ParetoFront:
125
136
see how much of a problem this is in practice before we try that.
126
137
"""
127
138
128
- def __init__ (self , random ) :
139
+ def __init__ (self , random : Random ) -> None :
129
140
self .__random = random
130
- self .__eviction_listeners = []
141
+ self .__eviction_listeners : list [ Callable [[ ConjectureResult ], None ]] = []
131
142
132
- self .front = SortedList (key = lambda d : sort_key (d .nodes ))
133
- self .__pending = None
143
+ self .front : SortedList [ConjectureResult ] = SortedList (
144
+ key = lambda d : sort_key (d .nodes )
145
+ )
146
+ self .__pending : Optional [ConjectureResult ] = None
134
147
135
- def add (self , data ) :
148
+ def add (self , data : Union [ ConjectureData , ConjectureResult , _Overrun ]) -> bool :
136
149
"""Attempts to add ``data`` to the pareto front. Returns True if
137
150
``data`` is now in the front, including if data is already in the
138
151
collection, and False otherwise"""
139
152
if data .status < Status .VALID :
140
153
return False
141
154
155
+ assert not isinstance (data , _Overrun )
142
156
data = data .as_result ()
157
+ data = cast (ConjectureResult , data )
143
158
144
159
if not self .front :
145
160
self .front .add (data )
@@ -166,7 +181,7 @@ def add(self, data):
166
181
# We track which values we are going to remove and remove them all
167
182
# at the end so the shape of the front doesn't change while we're
168
183
# using it.
169
- to_remove = []
184
+ to_remove : list [ ConjectureResult ] = []
170
185
171
186
# We now iteratively sample elements from the approximate pareto
172
187
# front to check whether they should be retained. When the set of
@@ -238,26 +253,26 @@ def add(self, data):
238
253
finally :
239
254
self .__pending = None
240
255
241
- def on_evict (self , f ) :
256
+ def on_evict (self , f : Callable [[ ConjectureResult ], None ]) -> None :
242
257
"""Register a listener function that will be called with data when it
243
258
gets removed from the front because something else dominates it."""
244
259
self .__eviction_listeners .append (f )
245
260
246
- def __contains__ (self , data ) :
261
+ def __contains__ (self , data : object ) -> bool :
247
262
return isinstance (data , (ConjectureData , ConjectureResult )) and (
248
263
data .as_result () in self .front
249
264
)
250
265
251
- def __iter__ (self ):
266
+ def __iter__ (self ) -> Iterator [ ConjectureResult ] :
252
267
return iter (self .front )
253
268
254
- def __getitem__ (self , i ) :
269
+ def __getitem__ (self , i : int ) -> ConjectureResult :
255
270
return self .front [i ]
256
271
257
- def __len__ (self ):
272
+ def __len__ (self ) -> int :
258
273
return len (self .front )
259
274
260
- def __remove (self , data ) :
275
+ def __remove (self , data : ConjectureResult ) -> None :
261
276
try :
262
277
self .front .remove (data )
263
278
except ValueError :
@@ -277,11 +292,12 @@ class ParetoOptimiser:
277
292
grow more powerful over time.
278
293
"""
279
294
280
- def __init__ (self , engine ) :
295
+ def __init__ (self , engine : "ConjectureRunner" ) -> None :
281
296
self .__engine = engine
282
- self .front = self .__engine .pareto_front
297
+ assert self .__engine .pareto_front is not None
298
+ self .front : ParetoFront = self .__engine .pareto_front
283
299
284
- def run (self ):
300
+ def run (self ) -> None :
285
301
seen = set ()
286
302
287
303
# We iterate backwards through the pareto front, using the shrinker to
0 commit comments