11# Builtin modules
22from __future__ import annotations
3- import os , traceback , unittest , signal as _signal
4- from threading import Timer , Event
3+ import traceback , signal as _signal
4+ from threading import Event
55from time import monotonic , sleep
66from typing import Callable , Dict , Any , Iterator , Iterable , Optional , Union
7+ from types import FrameType
8+ # Third party modules
79# Local modules
810# Program
11+ Signals = _signal .Signals
12+
913class KillSignal (Exception ): pass
1014
11- class SignalIterator (Iterator ):
15+ class SignalIterator (Iterator [ Any ] ):
1216 __slots__ = ("event" , "it" , "checkDelay" , "lastCheck" )
13- def __init__ (self , event :Event , it :Iterable , checkDelay :float = 1.0 ):
14- self .event :Event = event
15- self .it :Iterator = it .__iter__ ()
16- self .checkDelay :float = checkDelay
17- self .lastCheck :float = monotonic ()
18- def __iter__ (self ) -> Iterator :
17+ event :Event
18+ it :Iterator [Any ]
19+ checkDelay :float
20+ lastCheck :float
21+ def __init__ (self , event :Event , it :Iterable [Any ], checkDelay :float = 1.0 ):
22+ self .event = event
23+ self .it = it .__iter__ ()
24+ self .checkDelay = checkDelay
25+ self .lastCheck = monotonic ()
26+ def __iter__ (self ) -> Iterator [Any ]:
1927 return self
2028 def __next__ (self ) -> Any :
21- m : float = monotonic ()
29+ m = monotonic ()
2230 if m - self .lastCheck > self .checkDelay :
2331 self .lastCheck = m
2432 if self .event .is_set ():
@@ -28,38 +36,50 @@ def __next__(self) -> Any:
2836class BaseSignal :
2937 _force :bool
3038 @classmethod
31- def check (self ) -> bool :
32- if not isinstance (Signal ._handler , Signal ):
33- return False
34- return Signal . _handler . _check ( self . _force )
39+ def get (self ) -> bool :
40+ if isinstance (Signal ._handler , Signal ):
41+ return Signal . _handler . _get ( self . _force )
42+ return False
3543 @classmethod
36- def checkSoft (self ) -> bool :
37- if not isinstance (Signal ._handler , Signal ):
38- return False
39- return Signal . _handler . _check ( False )
44+ def getSoft (self ) -> bool :
45+ if isinstance (Signal ._handler , Signal ):
46+ return Signal . _handler . _get ( False )
47+ return False
4048 @classmethod
41- def checkHard (self ) -> bool :
42- if not isinstance (Signal ._handler , Signal ):
43- return False
44- return Signal ._handler ._check (True )
49+ def getHard (self ) -> bool :
50+ if isinstance (Signal ._handler , Signal ):
51+ return Signal ._handler ._get (True )
52+ return False
53+ @classmethod
54+ def check (self ) -> None :
55+ if isinstance (Signal ._handler , Signal ):
56+ return Signal ._handler ._check (self ._force )
57+ @classmethod
58+ def checkSoft (self ) -> None :
59+ if isinstance (Signal ._handler , Signal ):
60+ return Signal ._handler ._check (False )
61+ @classmethod
62+ def checkHard (self ) -> None :
63+ if isinstance (Signal ._handler , Signal ):
64+ return Signal ._handler ._check (True )
4565 @classmethod
4666 def sleep (self , seconds :Union [int , float ], raiseOnKill :bool = False ) -> None :
47- if not isinstance (Signal ._handler , Signal ):
48- return sleep (seconds )
49- return Signal . _handler . _sleep (seconds , raiseOnKill , self . _force )
67+ if isinstance (Signal ._handler , Signal ):
68+ return Signal . _handler . _sleep (seconds , raiseOnKill , self . _force )
69+ return sleep (seconds )
5070 @classmethod
51- def signalSoftKill (self , * args , ** kwargs ) -> None :
71+ def signalSoftKill (self , * args : Any , ** kwargs : Any ) -> None :
5272 if isinstance (Signal ._handler , Signal ):
5373 return Signal ._handler ._signalSoftKill (* args , ** kwargs )
5474 @classmethod
55- def signalHardKill (self , * args , ** kwargs ) -> None :
75+ def signalHardKill (self , * args : Any , ** kwargs : Any ) -> None :
5676 if isinstance (Signal ._handler , Signal ):
5777 return Signal ._handler ._signalHardKill (* args , ** kwargs )
5878 @classmethod
59- def iter (self , it :Iterable , checkDelay :float = 1.0 ) -> Iterable :
60- if not isinstance (Signal ._handler , Signal ):
61- return it
62- return Signal . _handler . _iter ( it , checkDelay , self . _force )
79+ def iter (self , it :Iterable [ Any ] , checkDelay :float = 1.0 ) -> Iterable [ Any ] :
80+ if isinstance (Signal ._handler , Signal ):
81+ return Signal . _handler . _iter ( it , checkDelay , self . _force )
82+ return it
6383 @classmethod
6484 def softKill (self ) -> None :
6585 if isinstance (Signal ._handler , Signal ):
@@ -89,16 +109,22 @@ class HardSignal(BaseSignal):
89109 _force :bool = True
90110
91111class Signal (HardSignal ):
112+ _handler :Optional [Signal ] = None
113+ softKillFn :Optional [Callable [[Signals , FrameType ], Any ]]
114+ hardKillFn :Optional [Callable [[Signals , FrameType ], Any ]]
115+ forceKillCounterFn :Optional [Callable [[int , int ], Any ]]
116+ counter :int
117+ forceCounter :int
92118 eSoft :Event
93119 eHard :Event
94- _handler :Optional [Signal ] = None
95- def __init__ ( self , softKillFn :Optional [Callable ] = None , hardKillFn : Optional [ Callable ]= None ,
96- forceKillCounterFn :Optional [Callable ]= None , forceCounter :int = 10 ):
97- self .softKillFn : Optional [ Callable ] = softKillFn
98- self .hardKillFn : Optional [ Callable ] = hardKillFn
99- self .forceKillCounterFn : Optional [ Callable ] = forceKillCounterFn
100- self .counter : int = 0
101- self .forceCounter : int = forceCounter
120+ def __init__ ( self , softKillFn :Optional [Callable [[ Signals , FrameType ], Any ]] = None ,
121+ hardKillFn :Optional [Callable [[ Signals , FrameType ], Any ] ]= None ,
122+ forceKillCounterFn :Optional [Callable [[ int , int ], Any ] ]= None , forceCounter :int = 10 ):
123+ self .softKillFn = softKillFn
124+ self .hardKillFn = hardKillFn
125+ self .forceKillCounterFn = forceKillCounterFn
126+ self .counter = 0
127+ self .forceCounter = forceCounter
102128 self .eSoft = Event ()
103129 self .eHard = Event ()
104130 Signal ._handler = self
@@ -123,16 +149,21 @@ def __setstate__(self, states:Dict[str, Any]) -> None:
123149 def _activate (self ) -> None :
124150 _signal .signal (_signal .SIGINT , Signal .signalSoftKill )
125151 _signal .signal (_signal .SIGTERM , Signal .signalHardKill )
126- def _check (self , force :bool = True ) -> bool :
152+ def _get (self , force :bool = True ) -> bool :
127153 if force :
128154 return self .eHard .is_set ()
129155 return self .eSoft .is_set ()
156+ def _check (self , force :bool = True ) -> None :
157+ if (force and self .eHard .is_set ()) or (not force and self .eSoft .is_set ()):
158+ raise KillSignal
159+ return None
130160 def _sleep (self , seconds :Union [int , float ], raiseOnKill :bool = False , force :bool = True ) -> None :
131161 if (self .eHard if force else self .eSoft ).wait (float (seconds )) and raiseOnKill :
132162 raise KillSignal
133- def _iter (self , it :Iterable , checkDelay :float = 1.0 , force :bool = True ) -> Iterator :
163+ return None
164+ def _iter (self , it :Iterable [Any ], checkDelay :float = 1.0 , force :bool = True ) -> Iterator [Any ]:
134165 return SignalIterator (self .eHard if force else self .eSoft , it , checkDelay )
135- def _signalSoftKill (self , * args , ** kwargs ) -> None :
166+ def _signalSoftKill (self , * args : Any , ** kwargs : Any ) -> None :
136167 self ._softKill ()
137168 if not self .eHard .is_set ():
138169 self .counter += 1
@@ -143,67 +174,26 @@ def _signalSoftKill(self, *args, **kwargs) -> None:
143174 traceback .print_exc ()
144175 if self .counter >= self .forceCounter :
145176 self ._hardKill ()
146- def _signalHardKill (self , * args , ** kwargs ) -> None :
177+ def _signalHardKill (self , * args : Any , ** kwargs : Any ) -> None :
147178 self ._softKill ()
148179 self ._hardKill ()
149180 def _softKill (self ) -> None :
150181 if not self .eSoft .is_set ():
151182 self .eSoft .set ()
152183 if callable (self .softKillFn ):
153184 try :
154- self .softKillFn ()
185+ self .softKillFn () # type: ignore
155186 except :
156187 traceback .print_exc ()
157188 def _hardKill (self ) -> None :
158189 if not self .eHard .is_set ():
159190 self .eHard .set ()
160191 if callable (self .hardKillFn ):
161192 try :
162- self .hardKillFn ()
193+ self .hardKillFn () # type: ignore
163194 except :
164195 traceback .print_exc ()
165196 def _reset (self ) -> None :
166197 self .eSoft .clear ()
167198 self .eHard .clear ()
168199 self .counter = 0
169-
170- class SignalTest (unittest .TestCase ):
171- rootSignal :Signal
172- @classmethod
173- def setUpClass (self ) -> None :
174- self .rootSignal = Signal ()
175- def tearDown (self ) -> None :
176- self .rootSignal .reset ()
177- def killmeTimer (self ) -> None :
178- def suicide ():
179- os .kill (os .getpid (), _signal .SIGINT )
180- Timer (1 , suicide ).start ()
181- def test_sleep (self ) -> None :
182- t :float = monotonic ()
183- self .rootSignal .sleep (2 )
184- self .assertGreater (monotonic ()- t , 2.0 )
185- def test_sleepRaise (self ) -> None :
186- self .killmeTimer ()
187- with self .assertRaises (KillSignal ):
188- self .rootSignal .getSoftSignal ().sleep (2 , raiseOnKill = True )
189- def test_iter (self ) -> None :
190- s :list = list (range (5 ))
191- d :list = []
192- i :int
193- signal :SoftSignal = self .rootSignal .getSoftSignal ()
194- self .killmeTimer ()
195- with self .assertRaises (KillSignal ):
196- for i in s :
197- signal .sleep (0.5 , raiseOnKill = True )
198- d .append (i )
199- def test_hardkill (self ) -> None :
200- self .killmeTimer ()
201- sleep (0.1 )
202- self .killmeTimer ()
203- sleep (0.1 )
204- self .killmeTimer ()
205- sleep (0.1 )
206- self .rootSignal .forceCounter = 3
207- with self .assertRaises (KillSignal ):
208- self .rootSignal .sleep (10 , raiseOnKill = True )
209- self .rootSignal .forceCounter = 10
0 commit comments