@@ -51,11 +51,13 @@ def tearDown(self):
5151 def _timeout_handler (self , signum , frame ):
5252 raise TimeoutError (
5353 "Test {self._testMethodName} took longer than 30s! Infinite Loop suspected." )
54-
54+
5555 def run_module_safely (self , module_name ):
5656 """Imports and runs a module with a strict 30-second timeout."""
5757 # Set an alarm for 30 seconds (Works on Linux/GitHub Actions)
5858 if hasattr (signal , 'SIGALRM' ):
59+ # Ensure any previous alarm is cleared
60+ signal .alarm (0 )
5961 signal .signal (signal .SIGALRM , self ._timeout_handler )
6062 signal .alarm (30 )
6163
@@ -80,6 +82,7 @@ def run_module_safely(self, module_name):
8082 raise e # Re-raise to fail the test
8183 else :
8284 print (f" -> [INFO] Script stopped with: { e } " , flush = True )
85+
8386 finally :
8487 if hasattr (signal , 'SIGALRM' ):
8588 signal .alarm (0 ) # Disable the alarm
@@ -108,7 +111,9 @@ def side_effect(*args, **kwargs):
108111 def test_01_k2400_iv_backend (self ):
109112 # GLOBAL PATCH for sleep is critical here
110113 with patch ('pymeasure.instruments.keithley.Keithley2400' ) as MockInst , \
111- patch ('time.sleep' , side_effect = self .get_circuit_breaker (5 )):
114+ patch ('time.sleep' , side_effect = self .get_circuit_breaker (5 )) as mock_sleep :
115+
116+ self .addCleanup (mock_sleep .stop )
112117
113118 spy = MockInst .return_value
114119 with patch ('builtins.input' , side_effect = ['100' , '10' , 'test_file' ]), \
@@ -118,8 +123,10 @@ def test_01_k2400_iv_backend(self):
118123 spy .enable_source .assert_called ()
119124
120125 def test_02_lakeshore_backend (self ):
121- with patch ('pyvisa.ResourceManager' ) as MockRM , \
122- patch ('time.sleep' , side_effect = self .get_circuit_breaker (15 )):
126+ with patch ('pyvisa.ResourceManager' ) as MockRM :
127+ mock_sleep = patch ('time.sleep' , side_effect = self .get_circuit_breaker (15 ))
128+ mock_sleep .start ()
129+ self .addCleanup (mock_sleep .stop )
123130
124131 spy = MockRM .return_value .open_resource .return_value
125132 spy .query .side_effect = [
@@ -136,10 +143,13 @@ def test_02_lakeshore_backend(self):
136143 patch ('matplotlib.pyplot.subplots' , return_value = (mock_fig , mock_ax )):
137144 self .run_module_safely (
138145 "Lakeshore_350_340.Backends.T_Control_L350_Simple_Backend_v10" )
139-
146+
140147 def test_03_k6517b_pyro_backend (self ):
141- with patch ('pymeasure.instruments.keithley.Keithley6517B' ) as MockInst , \
142- patch ('time.sleep' , side_effect = self .get_circuit_breaker (5 )):
148+ with patch ('pymeasure.instruments.keithley.Keithley6517B' ) as MockInst :
149+ mock_sleep = patch ('time.sleep' , side_effect = self .get_circuit_breaker (5 ))
150+ mock_sleep .start ()
151+ self .addCleanup (mock_sleep .stop )
152+
143153 spy = MockInst .return_value
144154 spy .current = 1.23e-9
145155 with patch ('pandas.DataFrame.to_csv' ):
@@ -149,16 +159,22 @@ def test_03_k6517b_pyro_backend(self):
149159 def test_04_lcr_keysight_backend (self ):
150160 with patch ('pymeasure.instruments.agilent.AgilentE4980' ), \
151161 patch ('pyvisa.ResourceManager' ) as MockRM , \
152- patch ('time.sleep' , side_effect = self .get_circuit_breaker (5 )):
162+ patch ('time.sleep' , side_effect = self .get_circuit_breaker (5 )) as mock_sleep :
163+
164+ self .addCleanup (mock_sleep .stop )
165+
153166 visa_spy = MockRM .return_value .open_resource .return_value
154167 visa_spy .query .return_value = "0.5"
155168 with patch ('pandas.DataFrame.to_csv' ):
156169 self .run_module_safely (
157170 "LCR_Keysight_E4980A.Backends.CV_KE4980A_Simple_Backend_v10" )
158171
159172 def test_05_delta_simple (self ):
160- with patch ('pyvisa.ResourceManager' ) as MockRM , \
161- patch ('time.sleep' , side_effect = self .get_circuit_breaker (10 )):
173+ with patch ('pyvisa.ResourceManager' ) as MockRM :
174+ mock_sleep = patch ('time.sleep' , side_effect = self .get_circuit_breaker (10 ))
175+ mock_sleep .start ()
176+ self .addCleanup (mock_sleep .stop )
177+
162178 MockRM .return_value .open_resource .return_value
163179 inputs = ['0' , '1e-5' , '1e-6' , 'test_file' , 'y' , 'y' ]
164180 with patch ('builtins.input' , side_effect = inputs ), \
@@ -167,8 +183,11 @@ def test_05_delta_simple(self):
167183 "Delta_mode_Keithley_6221_2182.Backends.Delta_K6221_K2182_Simple_v7" )
168184
169185 def test_06_delta_sensing (self ):
170- with patch ('pyvisa.ResourceManager' ) as MockRM , \
171- patch ('time.sleep' , side_effect = self .get_circuit_breaker (10 )):
186+ with patch ('pyvisa.ResourceManager' ) as MockRM :
187+ mock_sleep = patch ('time.sleep' , side_effect = self .get_circuit_breaker (10 ))
188+ mock_sleep .start ()
189+ self .addCleanup (mock_sleep .stop )
190+
172191 inst = MockRM .return_value .open_resource .return_value
173192 inst .query .return_value = "+1.23E-5"
174193 inputs = ['10' , '300' , '10' , 'test_file' , 'y' ]
@@ -181,8 +200,11 @@ def test_06_delta_sensing(self):
181200 print (" [SKIP] Module not found, skipping." )
182201
183202 def test_07_lockin_backend (self ):
184- with patch ('pyvisa.ResourceManager' ) as MockRM , \
185- patch ('time.sleep' , side_effect = self .get_circuit_breaker (5 )):
203+ with patch ('pyvisa.ResourceManager' ) as MockRM :
204+ mock_sleep = patch ('time.sleep' , side_effect = self .get_circuit_breaker (5 ))
205+ mock_sleep .start ()
206+ self .addCleanup (mock_sleep .stop )
207+
186208 spy = MockRM .return_value .open_resource .return_value
187209 spy .query .side_effect = [
188210 "SRS,SR830,s/n12345,ver1.07" , # *IDN?
@@ -197,7 +219,9 @@ def test_08_combined_2400_2182(self):
197219 # We suspect input mismatch or resource opening hang.
198220 with patch ('pyvisa.ResourceManager' ) as MockRM , \
199221 patch ('pymeasure.instruments.keithley.Keithley2400' ), \
200- patch ('time.sleep' , side_effect = self .get_circuit_breaker (10 )):
222+ patch ('time.sleep' , side_effect = self .get_circuit_breaker (10 )) as mock_sleep :
223+
224+ self .addCleanup (mock_sleep .stop )
201225
202226 rm = MockRM .return_value
203227 k2182_spy = MagicMock ()
@@ -214,16 +238,22 @@ def test_08_combined_2400_2182(self):
214238 "Keithley_2400_Keithley_2182.Backends.IV_K2400_K2182_Backend_v1" )
215239
216240 def test_09_poling (self ):
217- with patch ('pymeasure.instruments.keithley.Keithley6517B' ), \
218- patch ('time.sleep' , side_effect = self .get_circuit_breaker (5 )):
241+ with patch ('pymeasure.instruments.keithley.Keithley6517B' ):
242+ mock_sleep = patch ('time.sleep' , side_effect = self .get_circuit_breaker (5 ))
243+ mock_sleep .start ()
244+ self .addCleanup (mock_sleep .stop )
245+
219246 inputs = ['100' , '10' , 'y' ]
220247 with patch ('builtins.input' , side_effect = inputs ):
221248 self .run_module_safely (
222249 "Keithley_6517B.Pyroelectricity.Backends.Poling_K6517B_Backend_v10" )
223250
224251 def test_10_high_resistance (self ):
225- with patch ('pymeasure.instruments.keithley.Keithley6517B' ) as Mock6517 , \
226- patch ('time.sleep' , side_effect = self .get_circuit_breaker (5 )):
252+ with patch ('pymeasure.instruments.keithley.Keithley6517B' ) as Mock6517 :
253+ mock_sleep = patch ('time.sleep' , side_effect = self .get_circuit_breaker (5 ))
254+ mock_sleep .start ()
255+ self .addCleanup (mock_sleep .stop )
256+
227257 spy = Mock6517 .return_value
228258 spy .id = "Mocked Keithley 6517B"
229259 spy .resistance = 1.23e12 # Provide a mock resistance
@@ -249,8 +279,11 @@ def test_11_gpib_scanner(self):
249279 pass
250280
251281 def test_12_gpib_rescue (self ):
252- with patch ('pyvisa.ResourceManager' ) as MockRM , \
253- patch ('time.sleep' , side_effect = self .get_circuit_breaker (3 )):
282+ with patch ('pyvisa.ResourceManager' ) as MockRM :
283+ mock_sleep = patch ('time.sleep' , side_effect = self .get_circuit_breaker (3 ))
284+ mock_sleep .start ()
285+ self .addCleanup (mock_sleep .stop )
286+
254287 rm = MockRM .return_value
255288 rm .list_resources .return_value = ('GPIB0::1::INSTR' ,)
256289 self .run_module_safely (
0 commit comments