Coverage for jstark / feature_period.py: 87%

70 statements  

« prev     ^ index     » next       coverage.py v7.13.4, created at 2026-03-23 22:34 +0000

1""" 

2Encapsulate the period of a feature, defined by a unit of time 

3measure, a start and an end 

4""" 

5 

6from datetime import date 

7 

8from jstark.period_unit_of_measure import PeriodUnitOfMeasure 

9from .exceptions import FeaturePeriodEndGreaterThanStartError 

10 

11 

12class FeaturePeriod: 

13 """ 

14 Encapsulate the period of a feature, defined by a unit of time 

15 measure, a start and an end 

16 """ 

17 

18 def __init__( 

19 self, period_unit_of_measure: PeriodUnitOfMeasure, start: int, end: int 

20 ) -> None: 

21 if not isinstance(period_unit_of_measure, PeriodUnitOfMeasure): 

22 raise TypeError( 

23 ( 

24 "period_unit_of_measure needs to be of type " 

25 + f"PeriodUnitOfMeasure, not {type(period_unit_of_measure)}" 

26 ) 

27 ) 

28 if end > start: 

29 raise FeaturePeriodEndGreaterThanStartError(start=start, end=end) 

30 self.__period_unit_of_measure = period_unit_of_measure 

31 self.__start = start 

32 self.__end = end 

33 

34 @property 

35 def start(self) -> int: 

36 "Number of periods ago that the FeaturePeriod begins at" 

37 return self.__start 

38 

39 @property 

40 def end(self) -> int: 

41 "Number of periods ago that the FeaturePeriod ends at" 

42 return self.__end 

43 

44 @property 

45 def period_unit_of_measure(self) -> PeriodUnitOfMeasure: 

46 "Period unit of measure" 

47 return self.__period_unit_of_measure 

48 

49 @property 

50 def mnemonic(self) -> str: 

51 "Mnemonic for the feature period" 

52 return f"{self.start}{self.period_unit_of_measure.value}{self.end}" 

53 

54 @property 

55 def description(self) -> str: 

56 """Description of the feature period 

57 

58 Pretty sure this will change in time, but this initial implementation 

59 will do for now 

60 

61 Returns: 

62 str: description 

63 """ 

64 return ( 

65 f"Between {self.start} and {self.end} " 

66 + f"{self.period_unit_of_measure.name.lower()}s ago" 

67 ) 

68 

69 @property 

70 def number_of_periods(self) -> int: 

71 "Number of periods between start and end (inclusive)" 

72 return self.start - self.end + 1 

73 

74 def __str__(self) -> str: 

75 return self.description 

76 

77 def __repr__(self) -> str: 

78 return ( 

79 f"FeaturePeriod(" 

80 f"period_unit_of_measure={self.period_unit_of_measure}, " 

81 f"start={self.start}, end={self.end})" 

82 ) 

83 

84 def __eq__(self, other: object) -> bool: 

85 if not isinstance(other, FeaturePeriod): 

86 return False 

87 return ( 

88 self.period_unit_of_measure == other.period_unit_of_measure 

89 and self.start == other.start 

90 and self.end == other.end 

91 ) 

92 

93 def __hash__(self) -> int: 

94 return hash((self.period_unit_of_measure, self.start, self.end)) 

95 

96 

97TODAY = { 

98 "as_at": date.today(), 

99 "feature_periods": [FeaturePeriod(PeriodUnitOfMeasure.DAY, 0, 0)], 

100} 

101YESTERDAY = { 

102 "as_at": date.today(), 

103 "feature_periods": [FeaturePeriod(PeriodUnitOfMeasure.DAY, 1, 1)], 

104} 

105THIS_WEEK = { 

106 "as_at": date.today(), 

107 "feature_periods": [FeaturePeriod(PeriodUnitOfMeasure.WEEK, 0, 0)], 

108} 

109LAST_WEEK = { 

110 "as_at": date.today(), 

111 "feature_periods": [FeaturePeriod(PeriodUnitOfMeasure.WEEK, 1, 1)], 

112} 

113THIS_MONTH = { 

114 "as_at": date.today(), 

115 "feature_periods": [FeaturePeriod(PeriodUnitOfMeasure.MONTH, 0, 0)], 

116} 

117LAST_MONTH = { 

118 "as_at": date.today(), 

119 "feature_periods": [FeaturePeriod(PeriodUnitOfMeasure.MONTH, 1, 1)], 

120} 

121THIS_QUARTER = { 

122 "as_at": date.today(), 

123 "feature_periods": [FeaturePeriod(PeriodUnitOfMeasure.QUARTER, 0, 0)], 

124} 

125LAST_QUARTER = { 

126 "as_at": date.today(), 

127 "feature_periods": [FeaturePeriod(PeriodUnitOfMeasure.QUARTER, 1, 1)], 

128} 

129THIS_YEAR = { 

130 "as_at": date.today(), 

131 "feature_periods": [FeaturePeriod(PeriodUnitOfMeasure.YEAR, 0, 0)], 

132} 

133LAST_YEAR = { 

134 "as_at": date.today(), 

135 "feature_periods": [FeaturePeriod(PeriodUnitOfMeasure.YEAR, 1, 1)], 

136} 

137current_year = date.today().year 

138current_month = date.today().month 

139match current_month: 

140 case 1 | 2 | 3: 140 ↛ 142line 140 didn't jump to line 142 because the pattern on line 140 always matched

141 quarters_this_year = [1] 

142 case 4 | 5 | 6: 

143 quarters_this_year = [1, 2] 

144 case 7 | 8 | 9: 

145 quarters_this_year = [1, 2, 3] 

146 case _: # all other months: 

147 quarters_this_year = [1, 2, 3, 4] 

148ALL_MONTHS_LAST_YEAR = { 

149 "as_at": date(current_year, 1, 1), 

150 "feature_periods": [ 

151 FeaturePeriod(PeriodUnitOfMeasure.MONTH, i, i) for i in range(1, 13) 

152 ], 

153} 

154ALL_MONTHS_THIS_YEAR = { 

155 "as_at": date.today(), 

156 "feature_periods": [ 

157 FeaturePeriod(PeriodUnitOfMeasure.MONTH, i, i) for i in range(current_month) 

158 ], 

159} 

160ALL_QUARTERS_LAST_YEAR = { 

161 "as_at": date(current_year, 1, 1), 

162 "feature_periods": [ 

163 FeaturePeriod(PeriodUnitOfMeasure.QUARTER, i, i) for i in range(1, 5) 

164 ], 

165} 

166ALL_QUARTERS_THIS_YEAR = { 

167 "as_at": date.today(), 

168 "feature_periods": [ 

169 FeaturePeriod(PeriodUnitOfMeasure.QUARTER, i - 1, i - 1) 

170 for i in quarters_this_year 

171 ], 

172} 

173THIS_MONTH_VS_ONE_YEAR_PRIOR = { 

174 "as_at": date.today(), 

175 "feature_periods": [ 

176 FeaturePeriod(PeriodUnitOfMeasure.MONTH, 0, 0), 

177 FeaturePeriod(PeriodUnitOfMeasure.MONTH, 12, 12), 

178 ], 

179} 

180LAST_MONTH_VS_ONE_YEAR_PRIOR = { 

181 "as_at": date.today(), 

182 "feature_periods": [ 

183 FeaturePeriod(PeriodUnitOfMeasure.MONTH, 1, 1), 

184 FeaturePeriod(PeriodUnitOfMeasure.MONTH, 13, 13), 

185 ], 

186} 

187THIS_QUARTER_VS_ONE_YEAR_PRIOR = { 

188 "as_at": date.today(), 

189 "feature_periods": [ 

190 FeaturePeriod(PeriodUnitOfMeasure.QUARTER, 0, 0), 

191 FeaturePeriod(PeriodUnitOfMeasure.QUARTER, 4, 4), 

192 ], 

193} 

194 

195LAST_QUARTER_VS_ONE_YEAR_PRIOR = { 

196 "as_at": date.today(), 

197 "feature_periods": [ 

198 FeaturePeriod(PeriodUnitOfMeasure.QUARTER, 1, 1), 

199 FeaturePeriod(PeriodUnitOfMeasure.QUARTER, 5, 5), 

200 ], 

201} 

202 

203LAST_FIVE_YEARS = { 

204 "as_at": date.today(), 

205 "feature_periods": [ 

206 FeaturePeriod(PeriodUnitOfMeasure.YEAR, i, i) for i in range(1, 6) 

207 ], 

208}