@@ -63,7 +63,7 @@ def test_trigger_external_configures_input_line_and_timeout(patch_gentl_sdk, gen
6363 "selector" : "FrameStart" ,
6464 "source" : "Line0" ,
6565 "activation" : "RisingEdge" ,
66- "timeout" : 10.0 ,
66+ "timeout" : gb . GenTLCameraBackend . _MAX_HARDWARE_TRIGGER_FETCH_TIMEOUT ,
6767 },
6868 )
6969 be = gb .GenTLCameraBackend (settings )
@@ -76,7 +76,7 @@ def test_trigger_external_configures_input_line_and_timeout(patch_gentl_sdk, gen
7676 assert nm .TriggerActivation .value == "RisingEdge"
7777 assert nm .TriggerMode .value == "On"
7878 assert be .waits_for_hardware_trigger is True
79- assert be ._timeout == pytest .approx (10.0 )
79+ assert be ._timeout == pytest .approx (gb . GenTLCameraBackend . _MAX_HARDWARE_TRIGGER_FETCH_TIMEOUT )
8080
8181 ns = settings .properties ["gentl" ]
8282 assert ns ["trigger_actual" ]["role" ] == "external"
@@ -265,8 +265,12 @@ def test_trigger_alias_on_maps_to_external(patch_gentl_sdk, gentl_settings_facto
265265 be .close ()
266266
267267
268- def test_trigger_timeout_overrides_default_fetch_timeout (patch_gentl_sdk , gentl_settings_factory ):
268+ def test_trigger_timeout_is_capped_for_hardware_trigger_fetch_polling (
269+ patch_gentl_sdk ,
270+ gentl_settings_factory ,
271+ ):
269272 gb = patch_gentl_sdk
273+ expected_fetch_timeout = gb .GenTLCameraBackend ._MAX_HARDWARE_TRIGGER_FETCH_TIMEOUT
270274
271275 settings = _gentl_trigger_settings (
272276 gentl_settings_factory ,
@@ -277,18 +281,30 @@ def test_trigger_timeout_overrides_default_fetch_timeout(patch_gentl_sdk, gentl_
277281 )
278282 be = gb .GenTLCameraBackend (settings )
279283
280- be . open ()
281- assert be . _timeout == pytest . approx ( 7.5 )
284+ try :
285+ be . open ( )
282286
283- # Fake acquisition is started, so read should pass and record the timeout.
284- frame , _ = be .read ()
285- assert frame is not None
286- assert be ._acquirer .fetch_calls [- 1 ] == pytest .approx (7.5 )
287+ # Hardware-trigger fetch calls are intentionally capped so stop(wait=True)
288+ # is not blocked by a long user trigger timeout.
289+ assert be ._timeout == pytest .approx (expected_fetch_timeout )
287290
288- be .close ()
291+ # Fake acquisition is started, so read should pass and record the capped timeout.
292+ frame , _ = be .read ()
293+ assert frame is not None
294+ assert be ._acquirer .fetch_calls [- 1 ] == pytest .approx (expected_fetch_timeout )
295+
296+ # The requested trigger timeout is still preserved in persisted trigger_actual.
297+ actual = settings .properties ["gentl" ]["trigger_actual" ]
298+ assert actual ["timeout" ] == pytest .approx (7.5 )
289299
300+ finally :
301+ be .close ()
290302
291- def test_trigger_timeout_error_mentions_hardware_trigger_when_waiting (patch_gentl_sdk , gentl_settings_factory ):
303+
304+ def test_trigger_timeout_error_mentions_hardware_trigger_when_waiting (
305+ patch_gentl_sdk ,
306+ gentl_settings_factory ,
307+ ):
292308 gb = patch_gentl_sdk
293309
294310 settings = _gentl_trigger_settings (
@@ -297,22 +313,27 @@ def test_trigger_timeout_error_mentions_hardware_trigger_when_waiting(patch_gent
297313 "role" : "external" ,
298314 "timeout" : 3.0 ,
299315 },
300- # fast_start keeps acquisition stopped; fake fetch then raises timeout.
301- # This lets us assert the backend timeout message without hardware.
302316 )
317+ # fast_start keeps acquisition stopped; fake fetch then raises timeout.
318+ # This lets us assert the backend timeout message without hardware.
303319 settings .properties ["gentl" ]["fast_start" ] = True
320+
304321 be = gb .GenTLCameraBackend (settings )
305322
306- be .open ()
323+ try :
324+ be .open ()
307325
308- with pytest .raises (TimeoutError ) as ei :
309- be .read ()
326+ assert be ._timeout == pytest .approx (gb .GenTLCameraBackend ._MAX_HARDWARE_TRIGGER_FETCH_TIMEOUT )
310327
311- msg = str (ei .value ).lower ()
312- assert "gentl timeout" in msg
313- assert "hardware trigger" in msg or "trigger" in msg
328+ with pytest .raises (TimeoutError ) as ei :
329+ be .read ()
314330
315- be .close ()
331+ msg = str (ei .value ).lower ()
332+ assert "gentl timeout" in msg
333+ assert "hardware trigger" in msg or "trigger" in msg
334+
335+ finally :
336+ be .close ()
316337
317338
318339def test_trigger_actual_is_persisted_for_debugging (patch_gentl_sdk , gentl_settings_factory ):
@@ -330,16 +351,22 @@ def test_trigger_actual_is_persisted_for_debugging(patch_gentl_sdk, gentl_settin
330351 )
331352 be = gb .GenTLCameraBackend (settings )
332353
333- be .open ()
354+ try :
355+ be .open ()
334356
335- actual = settings .properties ["gentl" ].get ("trigger_actual" )
336- assert isinstance (actual , dict )
337- assert actual ["role" ] == "follower"
338- assert actual ["source" ] == "Line1"
339- assert actual ["activation" ] == "FallingEdge"
340- assert actual ["timeout" ] == pytest .approx (9.0 )
357+ # Requested timeout remains in trigger_actual for debugging/config visibility.
358+ actual = settings .properties ["gentl" ].get ("trigger_actual" )
359+ assert isinstance (actual , dict )
360+ assert actual ["role" ] == "follower"
361+ assert actual ["source" ] == "Line1"
362+ assert actual ["activation" ] == "FallingEdge"
363+ assert actual ["timeout" ] == pytest .approx (9.0 )
341364
342- be .close ()
365+ # But each blocking Harvester.fetch() call is capped for responsive shutdown.
366+ assert be ._timeout == pytest .approx (gb .GenTLCameraBackend ._MAX_HARDWARE_TRIGGER_FETCH_TIMEOUT )
367+
368+ finally :
369+ be .close ()
343370
344371
345372def test_trigger_invalid_selector_non_strict_disables_trigger (patch_gentl_sdk , gentl_settings_factory ):
@@ -372,3 +399,26 @@ def test_trigger_invalid_selector_non_strict_disables_trigger(patch_gentl_sdk, g
372399 assert actual ["role" ] == "off"
373400
374401 be .close ()
402+
403+
404+ def test_trigger_timeout_not_capped_for_master_mode (patch_gentl_sdk , gentl_settings_factory ):
405+ gb = patch_gentl_sdk
406+
407+ settings = _gentl_trigger_settings (
408+ gentl_settings_factory ,
409+ {
410+ "role" : "master" ,
411+ "timeout" : 7.5 ,
412+ },
413+ )
414+ be = gb .GenTLCameraBackend (settings )
415+
416+ try :
417+ be .open ()
418+
419+ # Master is free-running / trigger-generating, not waiting for hardware input.
420+ assert be .waits_for_hardware_trigger is False
421+ assert be ._timeout == pytest .approx (7.5 )
422+
423+ finally :
424+ be .close ()
0 commit comments