77import timeit
88import unittest
99from time import sleep , time
10- from typing import Callable
10+ from typing import Any , Callable , ContextManager , ParamSpec , TypeVar
1111
1212import six
1313
2727except ImportError :
2828 from genie_python .utilities import compress_and_hex , dehex_and_decompress
2929
30+ P = ParamSpec ("P" )
31+ T = TypeVar ("T" )
32+
3033WAIT_FOR_SERVER_TIMEOUT = 90
31- """Number of seconds to wait for a pv to become available in the config server e.g. when it starts or
32- when it changed config"""
34+ """Number of seconds to wait for a pv to become available in the
35+ config server e.g. when it starts or when it changed config"""
3336
3437# Number of seconds to wait for the DAE settings to update
3538DAE_MODE_TIMEOUT = 120
4144BASE_MEMORY_USAGE = "BASE_MEMORY_USAGE"
4245
4346
44- def parameterized_list (cases ) :
47+ def parameterized_list (cases : list [ Any ]) -> list [ tuple [ str , Any ]] :
4548 """
4649 Creates a list of cases for parameterized to use to run tests.
4750
@@ -68,7 +71,9 @@ def parameterized_list(cases):
6871 return return_list
6972
7073
71- def load_config_if_not_already_loaded (config_name ):
74+ def load_config_if_not_already_loaded (
75+ config_name : str , timeout : int = WAIT_FOR_SERVER_TIMEOUT
76+ ) -> None :
7277 """
7378 Load a config by name if it has not already been loaded.
7479
@@ -86,7 +91,7 @@ def load_config_if_not_already_loaded(config_name):
8691
8792 g .set_pv ("CS:BLOCKSERVER:LOAD_CONFIG" , value = compress_and_hex (config_name ), is_local = True )
8893 status_was_busy = False
89- for i in range (WAIT_FOR_SERVER_TIMEOUT ):
94+ for i in range (timeout ):
9095 status = get_server_status ()
9196 if status_was_busy and status == "" :
9297 break
@@ -103,19 +108,21 @@ def load_config_if_not_already_loaded(config_name):
103108 )
104109
105110
106- def _get_config_name ():
111+ def _get_config_name () -> str :
107112 """
108- Returns the current config name after waiting for up to WAIT_FOR_SERVER_TIMEOUT seconds for it to be readable
113+ Returns the current config name after waiting for up to WAIT_FOR_SERVER_TIMEOUT seconds
114+ for it to be readable
109115 Returns: the current configs name
110116 Raises: AssertionError if the cv can not be read
111117
112118 """
113119 return get_config_details ()["name" ]
114120
115121
116- def get_config_details ():
122+ def get_config_details () -> dict :
117123 """
118- Returns the current config name after waiting for up to WAIT_FOR_SERVER_TIMEOUT seconds for it to be readable
124+ Returns the current config name after waiting for up to WAIT_FOR_SERVER_TIMEOUT seconds
125+ for it to be readable
119126 Returns: the current configs name
120127 Raises: AssertionError if the cv can not be read
121128
@@ -136,7 +143,7 @@ def get_config_details():
136143 raise final_exception
137144
138145
139- def get_server_status ():
146+ def get_server_status () -> str | None :
140147 """
141148 Get the servers current status
142149
@@ -155,7 +162,7 @@ def get_server_status():
155162 return None
156163
157164
158- def set_genie_python_raises_exceptions (does_throw ) :
165+ def set_genie_python_raises_exceptions (does_throw : bool ) -> None :
159166 """
160167 Set that genie python api raises exceptions instead of just logging a message
161168 Args:
@@ -167,7 +174,7 @@ def set_genie_python_raises_exceptions(does_throw):
167174 genie_api_setup ._exceptions_raised = does_throw
168175
169176
170- def setup_simulated_wiring_tables (event_data = False ):
177+ def setup_simulated_wiring_tables (event_data : bool = False ) -> None :
171178 """
172179 Configures the DAE's wiring tables and sets the DAE to simulation mode
173180
@@ -206,7 +213,7 @@ def setup_simulated_wiring_tables(event_data=False):
206213 set_genie_python_raises_exceptions (False )
207214
208215
209- def _wait_for_and_assert_dae_simulation_mode (mode ) :
216+ def _wait_for_and_assert_dae_simulation_mode (mode : bool ) -> None :
210217 """
211218 Waits for specified DAE simulation mode in the DAE
212219
@@ -232,7 +239,7 @@ def _wait_for_and_assert_dae_simulation_mode(mode):
232239 )
233240
234241
235- def set_wait_for_complete_callback_dae_settings (wait ) :
242+ def set_wait_for_complete_callback_dae_settings (wait : bool ) -> None :
236243 """Sets the wait for completion callback attribute of the DAE
237244
238245 @param wait: Boolean value, True if you want the DAE to wait for the operation
@@ -241,13 +248,13 @@ def set_wait_for_complete_callback_dae_settings(wait):
241248 genie_api_setup .__api .dae .wait_for_completion_callback_dae_settings = wait
242249
243250
244- def temporarily_kill_icp ():
251+ def temporarily_kill_icp () -> ContextManager [ None ] :
245252 # Temporarily kills the ISIS ICP (ISIS DAE)
246253
247254 return genie_api_setup .__api .dae .temporarily_kill_icp ()
248255
249256
250- def as_seconds (time ) :
257+ def as_seconds (time : str ) -> int :
251258 """
252259 Convert a up time to seconds
253260 Args:
@@ -265,7 +272,7 @@ def as_seconds(time):
265272 return seconds
266273
267274
268- def _start_stop_ioc_is_a_start (is_a_start , ioc_name ) :
275+ def _start_stop_ioc_is_a_start (is_a_start : bool , ioc_name : str ) -> None :
269276 """
270277 Start or stop and ioc dependent on whether it "is_a_start"
271278 Args:
@@ -285,12 +292,13 @@ def _start_stop_ioc_is_a_start(is_a_start, ioc_name):
285292 wait_for_ioc_start_stop (timeout = IOCS_START_STOP_TIMEOUT , is_start = is_a_start , ioc_name = ioc_name )
286293
287294
288- def bulk_start_ioc (ioc_list ) :
295+ def bulk_start_ioc (ioc_list : list [ str ]) -> tuple [ list [ str ], list [ str ]] :
289296 """
290297 start a list of IOCs in bulk
291298 :param ioc_list: a list of the names of the IOCs to start
292299 :return: a list of IOCs that failed to start after IOCS_START_STOP_TIMEOUT seconds
293- and a list of any IOCs that were not present in proc serv (this should be a very rare case)
300+ and a list of any IOCs that were not present in proc serv
301+ (this should be a very rare case)
294302 """
295303 failed_to_start = []
296304 not_in_proc_serv = []
@@ -301,7 +309,8 @@ def bulk_start_ioc(ioc_list):
301309 except UnableToConnectToPVException :
302310 not_in_proc_serv .append (ioc_name )
303311 print (
304- f"{ ioc_name } not found in proc serv, should this be added to the list of iocs to skip?"
312+ f"{ ioc_name } not found in proc serv, should this be added "
313+ "to the list of iocs to skip?"
305314 )
306315 ioc_list = [ioc for ioc in ioc_list if ioc not in not_in_proc_serv ]
307316 for ioc_name in ioc_list :
@@ -314,7 +323,7 @@ def bulk_start_ioc(ioc_list):
314323 return failed_to_start , not_in_proc_serv
315324
316325
317- def bulk_stop_ioc (ioc_list ) :
326+ def bulk_stop_ioc (ioc_list : list [ str ]) -> list [ str ] :
318327 """
319328 Stops a list of IOCs in bulk
320329 :param ioc_list: a list of the names of the IOCs to stop
@@ -334,7 +343,7 @@ def bulk_stop_ioc(ioc_list):
334343 return failed_to_stop
335344
336345
337- def start_ioc (ioc_name ) :
346+ def start_ioc (ioc_name : str ) -> None :
338347 """
339348 Start the ioc
340349 Args:
@@ -346,7 +355,7 @@ def start_ioc(ioc_name):
346355 _start_stop_ioc_is_a_start (True , ioc_name )
347356
348357
349- def stop_ioc (ioc_name ) :
358+ def stop_ioc (ioc_name : str ) -> None :
350359 """
351360 Stop the ioc
352361 Args:
@@ -358,7 +367,7 @@ def stop_ioc(ioc_name):
358367 _start_stop_ioc_is_a_start (False , ioc_name )
359368
360369
361- def wait_for_ioc_start_stop (timeout , is_start , ioc_name ) :
370+ def wait_for_ioc_start_stop (timeout : int , is_start : bool , ioc_name : str ) -> None :
362371 """
363372 Wait for an ioc to start or stop, if timeout raise a timeout error
364373 Args:
@@ -382,9 +391,10 @@ def wait_for_ioc_start_stop(timeout, is_start, ioc_name):
382391 raise IOError (f"IOC { ioc_name } is not { 'started' if is_start else 'stopped' } " )
383392
384393
385- def quick_is_ioc_down (ioc_name ) :
394+ def quick_is_ioc_down (ioc_name : str ) -> bool :
386395 """
387- Determine if IOC is up by checking proc serv, cannot be used to make sure a PV has been started, but is
396+ Determine if IOC is up by checking proc serv, cannot be used to make sure a PV
397+ has been started, but is
388398 good enough for checks before attempting to start/stop
389399 :param ioc_name: The IOC to check
390400 :return: True if IOC is up; False otherwise
@@ -393,7 +403,7 @@ def quick_is_ioc_down(ioc_name):
393403 return running == "Shutdown"
394404
395405
396- def is_ioc_up (ioc_name ) :
406+ def is_ioc_up (ioc_name : str ) -> bool :
397407 """
398408 Determine if IOC is up by checking for the existence of its heartbeat PV
399409 Args:
@@ -411,7 +421,7 @@ def is_ioc_up(ioc_name):
411421 return heartbeat is not None
412422
413423
414- def wait_for_iocs_to_be_up (ioc_names , seconds_to_wait ) :
424+ def wait_for_iocs_to_be_up (ioc_names : list [ str ] , seconds_to_wait : int ) -> None :
415425 """
416426 Wait for a number of iocs to be up by checking for existence of heartbeat PVs for each ioc.
417427
@@ -432,11 +442,14 @@ def wait_for_iocs_to_be_up(ioc_names, seconds_to_wait):
432442 sleep (1 )
433443 else :
434444 raise AssertionError (
435- f"IOCs: { [ioc_name for ioc_name in ioc_names if not is_ioc_up (ioc_name )]} could not be started."
445+ f"IOCs: { [ioc_name for ioc_name in ioc_names if not is_ioc_up (ioc_name )]} "
446+ "could not be started."
436447 )
437448
438449
439- def wait_for_string_pvs_to_not_be_empty (pvs , seconds_to_wait , is_local = True ):
450+ def wait_for_string_pvs_to_not_be_empty (
451+ pvs : list [str ], seconds_to_wait : int , is_local : bool = True
452+ ) -> dict :
440453 """
441454 Wait for a number of string pvs to be non-empty and return their values.
442455 Raises an assertion error if at least one is not found.
@@ -469,16 +482,16 @@ def wait_for_string_pvs_to_not_be_empty(pvs, seconds_to_wait, is_local=True):
469482 return pv_values
470483
471484
472- def retry_on_failure (max_times ) :
485+ def retry_on_failure (max_times : int ) -> Callable [[ Callable [ P , T ]], Callable [ P , None ]] :
473486 """
474487 Decorator that will retry running a test if it failed.
475488 :param max_times: Maximum number of times to retry running the test
476489 :return: the decorator
477490 """
478491
479- def decorator (func ) :
492+ def decorator (func : Callable [ P , T ]) -> Callable [ P , None ] :
480493 @six .wraps (func )
481- def wrapper (* args , ** kwargs ) :
494+ def wrapper (* args : P . args , ** kwargs : P . kwargs ) -> None :
482495 err = None
483496 for attempt in range (max_times ):
484497 try :
@@ -497,7 +510,7 @@ def wrapper(*args, **kwargs):
497510 return decorator
498511
499512
500- def check_block_exists (block_name ) :
513+ def check_block_exists (block_name : str ) -> bool :
501514 """
502515 Check that the given block name is in the current blocks.
503516
@@ -511,10 +524,12 @@ def check_block_exists(block_name):
511524 return block_name in blocks
512525
513526
514- def retry_assert (retry_limit : int , func : Callable [[], None ], retry_time : float = 1.0 ):
527+ def retry_assert (retry_limit : int , func : Callable [[], None ], retry_time : float = 1.0 ) -> None :
515528 """
516- Take a function (func) that makes assertions. Try to call the function and catch any AssertionErrors if raised.
517- Repeat this until either the function does not raise an AssertionError or the retry_limit is reached.
529+ Take a function (func) that makes assertions. Try to call the function and
530+ catch any AssertionErrors if raised.
531+ Repeat this until either the function does not raise an AssertionError
532+ or the retry_limit is reached.
518533 If the retry limit is reach reraise the last error.
519534
520535 Args:
@@ -537,7 +552,7 @@ def retry_assert(retry_limit: int, func: Callable[[], None], retry_time: float =
537552 raise error
538553
539554
540- def get_execution_time (method ) :
555+ def get_execution_time (method : Callable [[], None ]) -> float :
541556 """
542557 Takes a method and calculates its execution time.
543558 Useful for tests that are time sensitive
@@ -556,7 +571,7 @@ def get_execution_time(method):
556571 return execution_time
557572
558573
559- def assert_with_timeout (assertion : Callable , timeout : int ):
574+ def assert_with_timeout (assertion : Callable [[], None ], timeout : int ) -> None :
560575 err = None
561576 for _ in range (timeout ):
562577 try :
0 commit comments