7
7
import timeit
8
8
import unittest
9
9
from time import sleep , time
10
- from typing import Callable
10
+ from typing import Callable , ParamSpec , TypeVar
11
11
12
12
import six
13
13
27
27
except ImportError :
28
28
from genie_python .utilities import compress_and_hex , dehex_and_decompress
29
29
30
+ P = ParamSpec ("P" )
31
+ T = TypeVar ("T" )
32
+
30
33
WAIT_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"""
33
36
34
37
# Number of seconds to wait for the DAE settings to update
35
38
DAE_MODE_TIMEOUT = 120
41
44
BASE_MEMORY_USAGE = "BASE_MEMORY_USAGE"
42
45
43
46
44
- def parameterized_list (cases ) :
47
+ def parameterized_list (cases : list [ str ]) -> list [ str ] :
45
48
"""
46
49
Creates a list of cases for parameterized to use to run tests.
47
50
@@ -68,7 +71,9 @@ def parameterized_list(cases):
68
71
return return_list
69
72
70
73
71
- def load_config_if_not_already_loaded (config_name , timeout = WAIT_FOR_SERVER_TIMEOUT ):
74
+ def load_config_if_not_already_loaded (
75
+ config_name : str , timeout : int = WAIT_FOR_SERVER_TIMEOUT
76
+ ) -> None :
72
77
"""
73
78
Load a config by name if it has not already been loaded.
74
79
@@ -103,19 +108,21 @@ def load_config_if_not_already_loaded(config_name, timeout=WAIT_FOR_SERVER_TIMEO
103
108
)
104
109
105
110
106
- def _get_config_name ():
111
+ def _get_config_name () -> str :
107
112
"""
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
109
115
Returns: the current configs name
110
116
Raises: AssertionError if the cv can not be read
111
117
112
118
"""
113
119
return get_config_details ()["name" ]
114
120
115
121
116
- def get_config_details ():
122
+ def get_config_details () -> dict () :
117
123
"""
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
119
126
Returns: the current configs name
120
127
Raises: AssertionError if the cv can not be read
121
128
@@ -136,7 +143,7 @@ def get_config_details():
136
143
raise final_exception
137
144
138
145
139
- def get_server_status ():
146
+ def get_server_status () -> str | None :
140
147
"""
141
148
Get the servers current status
142
149
@@ -155,7 +162,7 @@ def get_server_status():
155
162
return None
156
163
157
164
158
- def set_genie_python_raises_exceptions (does_throw ) :
165
+ def set_genie_python_raises_exceptions (does_throw : bool ) -> None :
159
166
"""
160
167
Set that genie python api raises exceptions instead of just logging a message
161
168
Args:
@@ -167,7 +174,7 @@ def set_genie_python_raises_exceptions(does_throw):
167
174
genie_api_setup ._exceptions_raised = does_throw
168
175
169
176
170
- def setup_simulated_wiring_tables (event_data = False ):
177
+ def setup_simulated_wiring_tables (event_data : bool = False ) -> None :
171
178
"""
172
179
Configures the DAE's wiring tables and sets the DAE to simulation mode
173
180
@@ -206,7 +213,7 @@ def setup_simulated_wiring_tables(event_data=False):
206
213
set_genie_python_raises_exceptions (False )
207
214
208
215
209
- def _wait_for_and_assert_dae_simulation_mode (mode ) :
216
+ def _wait_for_and_assert_dae_simulation_mode (mode : bool ) -> None :
210
217
"""
211
218
Waits for specified DAE simulation mode in the DAE
212
219
@@ -232,7 +239,7 @@ def _wait_for_and_assert_dae_simulation_mode(mode):
232
239
)
233
240
234
241
235
- def set_wait_for_complete_callback_dae_settings (wait ) :
242
+ def set_wait_for_complete_callback_dae_settings (wait : bool ) -> None :
236
243
"""Sets the wait for completion callback attribute of the DAE
237
244
238
245
@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):
241
248
genie_api_setup .__api .dae .wait_for_completion_callback_dae_settings = wait
242
249
243
250
244
- def temporarily_kill_icp ():
251
+ def temporarily_kill_icp () -> None :
245
252
# Temporarily kills the ISIS ICP (ISIS DAE)
246
253
247
254
return genie_api_setup .__api .dae .temporarily_kill_icp ()
248
255
249
256
250
- def as_seconds (time ) :
257
+ def as_seconds (time : str ) -> int :
251
258
"""
252
259
Convert a up time to seconds
253
260
Args:
@@ -265,7 +272,7 @@ def as_seconds(time):
265
272
return seconds
266
273
267
274
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 :
269
276
"""
270
277
Start or stop and ioc dependent on whether it "is_a_start"
271
278
Args:
@@ -285,12 +292,13 @@ def _start_stop_ioc_is_a_start(is_a_start, ioc_name):
285
292
wait_for_ioc_start_stop (timeout = IOCS_START_STOP_TIMEOUT , is_start = is_a_start , ioc_name = ioc_name )
286
293
287
294
288
- def bulk_start_ioc (ioc_list ) :
295
+ def bulk_start_ioc (ioc_list : list [ str ]) -> tuple [ bool , bool ] :
289
296
"""
290
297
start a list of IOCs in bulk
291
298
:param ioc_list: a list of the names of the IOCs to start
292
299
: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)
294
302
"""
295
303
failed_to_start = []
296
304
not_in_proc_serv = []
@@ -301,7 +309,8 @@ def bulk_start_ioc(ioc_list):
301
309
except UnableToConnectToPVException :
302
310
not_in_proc_serv .append (ioc_name )
303
311
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?"
305
314
)
306
315
ioc_list = [ioc for ioc in ioc_list if ioc not in not_in_proc_serv ]
307
316
for ioc_name in ioc_list :
@@ -314,7 +323,7 @@ def bulk_start_ioc(ioc_list):
314
323
return failed_to_start , not_in_proc_serv
315
324
316
325
317
- def bulk_stop_ioc (ioc_list ) :
326
+ def bulk_stop_ioc (ioc_list : list [ str ]) -> bool :
318
327
"""
319
328
Stops a list of IOCs in bulk
320
329
:param ioc_list: a list of the names of the IOCs to stop
@@ -334,7 +343,7 @@ def bulk_stop_ioc(ioc_list):
334
343
return failed_to_stop
335
344
336
345
337
- def start_ioc (ioc_name ) :
346
+ def start_ioc (ioc_name : str ) -> None :
338
347
"""
339
348
Start the ioc
340
349
Args:
@@ -346,7 +355,7 @@ def start_ioc(ioc_name):
346
355
_start_stop_ioc_is_a_start (True , ioc_name )
347
356
348
357
349
- def stop_ioc (ioc_name ) :
358
+ def stop_ioc (ioc_name : str ) -> None :
350
359
"""
351
360
Stop the ioc
352
361
Args:
@@ -358,7 +367,7 @@ def stop_ioc(ioc_name):
358
367
_start_stop_ioc_is_a_start (False , ioc_name )
359
368
360
369
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 :
362
371
"""
363
372
Wait for an ioc to start or stop, if timeout raise a timeout error
364
373
Args:
@@ -382,9 +391,10 @@ def wait_for_ioc_start_stop(timeout, is_start, ioc_name):
382
391
raise IOError (f"IOC { ioc_name } is not { 'started' if is_start else 'stopped' } " )
383
392
384
393
385
- def quick_is_ioc_down (ioc_name ) :
394
+ def quick_is_ioc_down (ioc_name : str ) -> bool :
386
395
"""
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
388
398
good enough for checks before attempting to start/stop
389
399
:param ioc_name: The IOC to check
390
400
:return: True if IOC is up; False otherwise
@@ -393,7 +403,7 @@ def quick_is_ioc_down(ioc_name):
393
403
return running == "Shutdown"
394
404
395
405
396
- def is_ioc_up (ioc_name ) :
406
+ def is_ioc_up (ioc_name : str ) -> bool :
397
407
"""
398
408
Determine if IOC is up by checking for the existence of its heartbeat PV
399
409
Args:
@@ -411,7 +421,7 @@ def is_ioc_up(ioc_name):
411
421
return heartbeat is not None
412
422
413
423
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 :
415
425
"""
416
426
Wait for a number of iocs to be up by checking for existence of heartbeat PVs for each ioc.
417
427
@@ -432,11 +442,14 @@ def wait_for_iocs_to_be_up(ioc_names, seconds_to_wait):
432
442
sleep (1 )
433
443
else :
434
444
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."
436
447
)
437
448
438
449
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 ():
440
453
"""
441
454
Wait for a number of string pvs to be non-empty and return their values.
442
455
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):
469
482
return pv_values
470
483
471
484
472
- def retry_on_failure (max_times ) :
485
+ def retry_on_failure (max_times : int ) -> Callable [[], None ] :
473
486
"""
474
487
Decorator that will retry running a test if it failed.
475
488
:param max_times: Maximum number of times to retry running the test
476
489
:return: the decorator
477
490
"""
478
491
479
- def decorator (func ) :
492
+ def decorator (func : Callable [ P , T ]) -> Callable [ P , T ] :
480
493
@six .wraps (func )
481
- def wrapper (* args , ** kwargs ) :
494
+ def wrapper (* args : P . args , ** kwargs : P . kwargs ) -> T :
482
495
err = None
483
496
for attempt in range (max_times ):
484
497
try :
@@ -497,7 +510,7 @@ def wrapper(*args, **kwargs):
497
510
return decorator
498
511
499
512
500
- def check_block_exists (block_name ) :
513
+ def check_block_exists (block_name : str ) -> bool :
501
514
"""
502
515
Check that the given block name is in the current blocks.
503
516
@@ -511,10 +524,12 @@ def check_block_exists(block_name):
511
524
return block_name in blocks
512
525
513
526
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 :
515
528
"""
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.
518
533
If the retry limit is reach reraise the last error.
519
534
520
535
Args:
@@ -537,7 +552,7 @@ def retry_assert(retry_limit: int, func: Callable[[], None], retry_time: float =
537
552
raise error
538
553
539
554
540
- def get_execution_time (method ) :
555
+ def get_execution_time (method : Callable [[], None ]) -> float :
541
556
"""
542
557
Takes a method and calculates its execution time.
543
558
Useful for tests that are time sensitive
@@ -556,7 +571,7 @@ def get_execution_time(method):
556
571
return execution_time
557
572
558
573
559
- def assert_with_timeout (assertion : Callable , timeout : int ):
574
+ def assert_with_timeout (assertion : Callable [[], None ], timeout : int ) -> None :
560
575
err = None
561
576
for _ in range (timeout ):
562
577
try :
0 commit comments