Coverage for src/sensai/util/helper.py: 73%

37 statements  

« prev     ^ index     » next       coverage.py v7.6.1, created at 2024-11-29 18:29 +0000

1""" 

2This module contains various helper functions. 

3""" 

4import math 

5from typing import Any, Sequence, Union, TypeVar, List, Optional, Dict, Container, Iterable 

6 

7T = TypeVar("T") 

8 

9 

10def count_none(*args: Any) -> int: 

11 """ 

12 Counts the number of arguments that are None 

13 

14 :param args: various arguments 

15 :return: the number of arguments that are None 

16 """ 

17 c = 0 

18 for a in args: 

19 if a is None: 

20 c += 1 

21 return c 

22 

23 

24def count_not_none(*args: Any) -> int: 

25 """ 

26 Counts the number of arguments that are not None 

27 

28 :param args: various arguments 

29 :return: the number of arguments that are not None 

30 """ 

31 return len(args) - count_none(*args) 

32 

33 

34def any_none(*args: Any) -> bool: 

35 """ 

36 :param args: various arguments 

37 :return: True if any of the arguments are None, False otherwise 

38 """ 

39 return count_none(*args) > 0 

40 

41 

42def all_none(*args: Any) -> bool: 

43 """ 

44 :param args: various arguments 

45 :return: True if all of the arguments are None, False otherwise 

46 """ 

47 return count_none(*args) == len(args) 

48 

49 

50def check_not_nan_dict(d: dict): 

51 """ 

52 Raises ValueError if any of the values in the given dictionary are NaN, reporting the respective keys 

53 

54 :param d: a dictionary mapping to floats that are to be checked for NaN 

55 """ 

56 invalid_keys = [k for k, v in d.items() if math.isnan(v)] 

57 if len(invalid_keys) > 0: 

58 raise ValueError(f"Got one or more NaN values: {invalid_keys}") 

59 

60 

61def contains_any(container: Union[Container, Iterable], items: Sequence) -> bool: 

62 for item in items: 

63 if item in container: 

64 return True 

65 return False 

66 

67 

68# noinspection PyUnusedLocal 

69def mark_used(*args): 

70 """ 

71 Utility function to mark identifiers as used. 

72 The function does nothing. 

73 

74 :param args: pass identifiers that shall be marked as used here 

75 """ 

76 pass 

77 

78 

79def flatten_arguments(args: Sequence[Union[T, Sequence[T]]]) -> List[T]: 

80 """ 

81 Main use case is to support both interfaces of the type f(T1, T2, ...) and f([T1, T2, ...]) simultaneously. 

82 It is assumed that if the latter form is passed, the arguments are either in a list or a tuple. Moreover, 

83 T cannot be a tuple or a list itself. 

84 

85 Overall this function is not all too safe and one should be aware of what one is doing when using it 

86 """ 

87 result = [] 

88 for arg in args: 

89 if isinstance(arg, list) or isinstance(arg, tuple): 

90 result.extend(arg) 

91 else: 

92 result.append(arg) 

93 return result 

94 

95 

96def kwarg_if_not_none(arg_name: str, arg_value: Any) -> Dict[str, Any]: 

97 """ 

98 Supports the optional passing of a kwarg, returning a non-empty dictionary with the kwarg only 

99 if the value is not None. 

100 

101 This can be helpful to improve backward compatibility for cases where a kwarg was added later 

102 but old implementations weren't updated to have it, such that an exception will be raised only 

103 if the kwarg is actually used. 

104 

105 :param arg_name: the argument name 

106 :param arg_value: the value 

107 :return: a dictionary containing the kwarg or, if the value is None, an empty dictionary 

108 """ 

109 if arg_value is None: 

110 return {} 

111 else: 

112 return {arg_name: arg_value}