1
1
import time as real_time
2
2
from inspect import Signature
3
3
from math import isfinite
4
- from typing import Any , Callable
4
+ from typing import Any , Literal
5
5
6
- from crosshair .core import FunctionInterps
6
+ from crosshair .core import register_patch
7
7
from crosshair .register_contract import register_contract
8
8
from crosshair .statespace import context_statespace
9
9
from crosshair .tracers import NoTracing
10
10
11
11
12
- def _gte_last (fn : Callable , value : Any ) -> bool :
12
+ class EarliestPossibleTime :
13
+ monotonic : float = 0.0
14
+ process_time : float = 0.0
15
+
16
+ def __init__ (self , * a ):
17
+ pass
18
+
19
+
20
+ # Imprecision at high values becomes a sort of artificial problem
21
+ _UNREALISTICALLY_LARGE_TIME_FLOAT = float (60 * 60 * 24 * 365 * 100_000 )
22
+
23
+
24
+ def _gte_last (kind : Literal ["monotonic" , "process_time" ], value : Any ) -> bool :
25
+ with NoTracing ():
26
+ earliest_times = context_statespace ().extra (EarliestPossibleTime )
27
+ threshold = getattr (earliest_times , kind )
28
+ setattr (earliest_times , kind , value )
29
+ return all ([threshold <= value , value < _UNREALISTICALLY_LARGE_TIME_FLOAT ])
30
+
31
+
32
+ def _sleep (value : float ) -> None :
13
33
with NoTracing ():
14
- interps = context_statespace ().extra (FunctionInterps )
15
- previous = interps ._interpretations [fn ]
16
- if len (previous ) < 2 :
17
- return True
18
- return value >= previous [- 2 ]
34
+ earliest_times = context_statespace ().extra (EarliestPossibleTime )
35
+ earliest_times .monotonic += value
36
+ return None
19
37
20
38
21
39
def make_registrations ():
22
40
register_contract (
23
41
real_time .time ,
24
- post = lambda __return__ : __return__ > 0.0 ,
42
+ post = lambda __return__ : __return__ > 0.0 and isfinite ( __return__ ) ,
25
43
sig = Signature (parameters = [], return_annotation = float ),
26
44
)
27
45
register_contract (
@@ -31,23 +49,24 @@ def make_registrations():
31
49
)
32
50
register_contract (
33
51
real_time .monotonic ,
34
- post = lambda __return__ : isfinite ( __return__ )
35
- and _gte_last ( real_time . monotonic , __return__ ),
52
+ post = lambda __return__ : _gte_last ( "monotonic" , __return__ )
53
+ and isfinite ( __return__ ),
36
54
sig = Signature (parameters = [], return_annotation = float ),
37
55
)
38
56
register_contract (
39
57
real_time .monotonic_ns ,
40
- post = lambda __return__ : isfinite (__return__ )
41
- and _gte_last (real_time .monotonic_ns , __return__ ),
58
+ post = lambda __return__ : _gte_last ("monotonic" , __return__ / 1_000_000_000 ),
42
59
sig = Signature (parameters = [], return_annotation = int ),
43
60
)
44
61
register_contract (
45
62
real_time .process_time ,
46
- post = lambda __return__ : _gte_last (real_time .process_time , __return__ ),
63
+ post = lambda __return__ : _gte_last ("process_time" , __return__ )
64
+ and isfinite (__return__ ),
47
65
sig = Signature (parameters = [], return_annotation = float ),
48
66
)
49
67
register_contract (
50
68
real_time .process_time_ns ,
51
- post = lambda __return__ : _gte_last (real_time . process_time_ns , __return__ ),
69
+ post = lambda __return__ : _gte_last ("process_time" , __return__ / 1_000_000_000 ),
52
70
sig = Signature (parameters = [], return_annotation = int ),
53
71
)
72
+ register_patch (real_time .sleep , _sleep )
0 commit comments