Coverage for src / toolbox_python / generators.py: 100%

18 statements  

« prev     ^ index     » next       coverage.py v7.13.1, created at 2026-01-02 22:56 +0000

1# ============================================================================ # 

2# # 

3# Title : Generators # 

4# Purpose : Generate information as needed. # 

5# # 

6# ============================================================================ # 

7 

8 

9# ---------------------------------------------------------------------------- # 

10# # 

11# Overview #### 

12# # 

13# ---------------------------------------------------------------------------- # 

14 

15 

16# ---------------------------------------------------------------------------- # 

17# Description #### 

18# ---------------------------------------------------------------------------- # 

19 

20 

21""" 

22!!! note "Summary" 

23 This module provides functions to generate information as needed. Such functions are typically used to generate data that is not stored in a database or file, but rather computed on-the-fly based on input parameters. 

24""" 

25 

26 

27# ---------------------------------------------------------------------------- # 

28# # 

29# Setup #### 

30# # 

31# ---------------------------------------------------------------------------- # 

32 

33 

34## --------------------------------------------------------------------------- # 

35## Import #### 

36## --------------------------------------------------------------------------- # 

37 

38 

39# ## Python Third Party Imports ---- 

40from typeguard import typechecked 

41 

42# ## Local First Party Imports ---- 

43from toolbox_python.checkers import assert_is_valid 

44 

45 

46## --------------------------------------------------------------------------- # 

47## Exports #### 

48## --------------------------------------------------------------------------- # 

49 

50 

51__all__: list[str] = ["generate_group_cutoffs"] 

52 

53 

54# ---------------------------------------------------------------------------- # 

55# # 

56# Groupings #### 

57# # 

58# ---------------------------------------------------------------------------- # 

59 

60 

61@typechecked 

62def generate_group_cutoffs( 

63 total_number: int, 

64 num_groups: int, 

65) -> tuple[tuple[int, int], ...]: 

66 """ 

67 !!! note "Summary" 

68 Generate group cutoffs for a given total number and number of groups. 

69 

70 !!! abstract "Details" 

71 This function divides a total number of items into a specified number of groups, returning a `#!py tuple` of `#!py tuple`'s where each inner `#!py tuple` contains the start and end indices for each group. The last group may contain fewer items if the total number is not evenly divisible by the number of groups. 

72 

73 Params: 

74 total_number (int): 

75 The total number of items to be divided into groups. 

76 num_groups (int): 

77 The number of groups to create. 

78 

79 Raises: 

80 (TypeCheckError): 

81 If any of the inputs parsed to the parameters of this function are not the correct type. Uses the [`@typeguard.typechecked`](https://typeguard.readthedocs.io/en/stable/api.html#typeguard.typechecked) decorator. 

82 (ValueError): 

83 If `total_number` is less than 1, or if `num_groups` is less than 1, or if `total_number` is less than `num_groups`. Uses the [`assert_is_valid`][toolbox_python.checkers.assert_is_valid] function to validate the inputs. 

84 

85 Returns: 

86 (tuple[tuple[int, int], ...]): 

87 A tuple of tuples, where each inner tuple contains the start and end indices for each group. The last group may have a different size if the total number is not evenly divisible by the number of groups. 

88 

89 ???+ example "Examples" 

90 

91 ```pycon {.py .python linenums="1" title="Prepare data"} 

92 >>> from toolbox_python.generators import generate_group_cutoffs 

93 ``` 

94 

95 ```pycon {.py .python linenums="1" title="Example 1: Basic usage"} 

96 >>> generate_group_cutoffs(10, 3) 

97 ``` 

98 <div class="result" markdown> 

99 ```{.sh .shell title="Output"} 

100 ((0, 3), (3, 6), (6, 11)) 

101 ``` 

102 !!! success "Conclusion: Successfully split 10 items into 3 groups." 

103 </div> 

104 

105 ```pycon {.py .python linenums="1" title="Example 2: Uneven groups"} 

106 >>> generate_group_cutoffs(10, 4) 

107 ``` 

108 <div class="result" markdown> 

109 ```{.sh .shell title="Output"} 

110 ((0, 3), (3, 6), (6, 9), (9, 11)) 

111 ``` 

112 !!! success "Conclusion: Successfully split 10 items into 4 groups, with the last group having fewer items." 

113 </div> 

114 

115 ```pycon {.py .python linenums="1" title="Example 3: Single group"} 

116 >>> generate_group_cutoffs(10, 1) 

117 ``` 

118 <div class="result" markdown> 

119 ```{.sh .shell title="Output"} 

120 ((0, 11),) 

121 ``` 

122 !!! success "Conclusion: Successfully created a single group containing all items." 

123 </div> 

124 

125 ```pycon {.py .python linenums="1" title="Example 4: Zero groups"} 

126 >>> generate_group_cutoffs(10, 0) 

127 ``` 

128 <div class="result" markdown> 

129 ```{.sh .shell title="Output"} 

130 ValueError: Validation failed: 'num_groups > 0' is not True 

131 ``` 

132 !!! failure "Conclusion: Cannot create groups with zero groups specified." 

133 </div> 

134 

135 ```pycon {.py .python linenums="1" title="Example 5: Negative total number"} 

136 >>> generate_group_cutoffs(-10, 3) 

137 ``` 

138 <div class="result" markdown> 

139 ```{.sh .shell title="Output"} 

140 ValueError: Validation failed: 'total_number > 0' is not True 

141 ``` 

142 !!! failure "Conclusion: Total number must be greater than 0." 

143 </div> 

144 

145 ```pycon {.py .python linenums="1" title="Example 6: Total number less than groups"} 

146 >>> generate_group_cutoffs(3, 5) 

147 ``` 

148 <div class="result" markdown> 

149 ```{.sh .shell title="Output"} 

150 ValueError: Validation failed: 'total_number >= num_groups' is not True 

151 ``` 

152 !!! failure "Conclusion: Total number must be greater than or equal to the number of groups." 

153 </div> 

154 """ 

155 

156 # Validations 

157 assert_is_valid(total_number, ">", 0) 

158 assert_is_valid(num_groups, ">", 0) 

159 assert_is_valid(total_number, ">=", num_groups) 

160 

161 # Calculate the size of each group 

162 group_size: int = total_number // num_groups 

163 

164 # List to store all group cutoffs 

165 cutoffs: list[tuple[int, int]] = [] 

166 

167 # Calculate the number of items that will be in the last group 

168 current_start: int = 0 

169 

170 # Loop through the number of groups to calculate start and end indices 

171 for group in range(num_groups): 

172 

173 # For the last group, end is total_number + 1 

174 if group == num_groups - 1: 

175 current_end: int = total_number + 1 

176 else: 

177 current_end: int = current_start + group_size 

178 

179 # Add the current group cutoff to the list 

180 cutoffs.append((current_start, current_end)) 

181 

182 # Update the start index for the next group 

183 current_start: int = current_end 

184 

185 # Convert the list to a tuple of tuples 

186 return tuple(cutoffs)