Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.10/site-packages/django/db/models/functions/math.py: 78%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

116 statements  

1import math 

2 

3from django.db.models.expressions import Func, Value 

4from django.db.models.fields import FloatField, IntegerField 

5from django.db.models.functions import Cast 

6from django.db.models.functions.mixins import ( 

7 FixDecimalInputMixin, 

8 NumericOutputFieldMixin, 

9) 

10from django.db.models.lookups import Transform 

11 

12 

13class Abs(Transform): 

14 function = "ABS" 

15 lookup_name = "abs" 

16 

17 

18class ACos(NumericOutputFieldMixin, Transform): 

19 function = "ACOS" 

20 lookup_name = "acos" 

21 

22 

23class ASin(NumericOutputFieldMixin, Transform): 

24 function = "ASIN" 

25 lookup_name = "asin" 

26 

27 

28class ATan(NumericOutputFieldMixin, Transform): 

29 function = "ATAN" 

30 lookup_name = "atan" 

31 

32 

33class ATan2(NumericOutputFieldMixin, Func): 

34 function = "ATAN2" 

35 arity = 2 

36 

37 def as_sqlite(self, compiler, connection, **extra_context): 

38 if not getattr( 

39 connection.ops, "spatialite", False 

40 ) or connection.ops.spatial_version >= (5, 0, 0): 

41 return self.as_sql(compiler, connection) 

42 # This function is usually ATan2(y, x), returning the inverse tangent 

43 # of y / x, but it's ATan2(x, y) on SpatiaLite < 5.0.0. 

44 # Cast integers to float to avoid inconsistent/buggy behavior if the 

45 # arguments are mixed between integer and float or decimal. 

46 # https://www.gaia-gis.it/fossil/libspatialite/tktview?name=0f72cca3a2 

47 clone = self.copy() 

48 clone.set_source_expressions( 

49 [ 

50 ( 

51 Cast(expression, FloatField()) 

52 if isinstance(expression.output_field, IntegerField) 

53 else expression 

54 ) 

55 for expression in self.get_source_expressions()[::-1] 

56 ] 

57 ) 

58 return clone.as_sql(compiler, connection, **extra_context) 

59 

60 

61class Ceil(Transform): 

62 function = "CEILING" 

63 lookup_name = "ceil" 

64 

65 def as_oracle(self, compiler, connection, **extra_context): 

66 return super().as_sql(compiler, connection, function="CEIL", **extra_context) 

67 

68 

69class Cos(NumericOutputFieldMixin, Transform): 

70 function = "COS" 

71 lookup_name = "cos" 

72 

73 

74class Cot(NumericOutputFieldMixin, Transform): 

75 function = "COT" 

76 lookup_name = "cot" 

77 

78 def as_oracle(self, compiler, connection, **extra_context): 

79 return super().as_sql( 

80 compiler, connection, template="(1 / TAN(%(expressions)s))", **extra_context 

81 ) 

82 

83 

84class Degrees(NumericOutputFieldMixin, Transform): 

85 function = "DEGREES" 

86 lookup_name = "degrees" 

87 

88 def as_oracle(self, compiler, connection, **extra_context): 

89 return super().as_sql( 

90 compiler, 

91 connection, 

92 template="((%%(expressions)s) * 180 / %s)" % math.pi, 

93 **extra_context, 

94 ) 

95 

96 

97class Exp(NumericOutputFieldMixin, Transform): 

98 function = "EXP" 

99 lookup_name = "exp" 

100 

101 

102class Floor(Transform): 

103 function = "FLOOR" 

104 lookup_name = "floor" 

105 

106 

107class Ln(NumericOutputFieldMixin, Transform): 

108 function = "LN" 

109 lookup_name = "ln" 

110 

111 

112class Log(FixDecimalInputMixin, NumericOutputFieldMixin, Func): 

113 function = "LOG" 

114 arity = 2 

115 

116 def as_sqlite(self, compiler, connection, **extra_context): 

117 if not getattr(connection.ops, "spatialite", False): 

118 return self.as_sql(compiler, connection) 

119 # This function is usually Log(b, x) returning the logarithm of x to 

120 # the base b, but on SpatiaLite it's Log(x, b). 

121 clone = self.copy() 

122 clone.set_source_expressions(self.get_source_expressions()[::-1]) 

123 return clone.as_sql(compiler, connection, **extra_context) 

124 

125 

126class Mod(FixDecimalInputMixin, NumericOutputFieldMixin, Func): 

127 function = "MOD" 

128 arity = 2 

129 

130 

131class Pi(NumericOutputFieldMixin, Func): 

132 function = "PI" 

133 arity = 0 

134 

135 def as_oracle(self, compiler, connection, **extra_context): 

136 return super().as_sql( 

137 compiler, connection, template=str(math.pi), **extra_context 

138 ) 

139 

140 

141class Power(NumericOutputFieldMixin, Func): 

142 function = "POWER" 

143 arity = 2 

144 

145 

146class Radians(NumericOutputFieldMixin, Transform): 

147 function = "RADIANS" 

148 lookup_name = "radians" 

149 

150 def as_oracle(self, compiler, connection, **extra_context): 

151 return super().as_sql( 

152 compiler, 

153 connection, 

154 template="((%%(expressions)s) * %s / 180)" % math.pi, 

155 **extra_context, 

156 ) 

157 

158 

159class Random(NumericOutputFieldMixin, Func): 

160 function = "RANDOM" 

161 arity = 0 

162 

163 def as_mysql(self, compiler, connection, **extra_context): 

164 return super().as_sql(compiler, connection, function="RAND", **extra_context) 

165 

166 def as_oracle(self, compiler, connection, **extra_context): 

167 return super().as_sql( 

168 compiler, connection, function="DBMS_RANDOM.VALUE", **extra_context 

169 ) 

170 

171 def as_sqlite(self, compiler, connection, **extra_context): 

172 return super().as_sql(compiler, connection, function="RAND", **extra_context) 

173 

174 def get_group_by_cols(self): 

175 return [] 

176 

177 

178class Round(FixDecimalInputMixin, Transform): 

179 function = "ROUND" 

180 lookup_name = "round" 

181 arity = None # Override Transform's arity=1 to enable passing precision. 

182 

183 def __init__(self, expression, precision=0, **extra): 

184 super().__init__(expression, precision, **extra) 

185 

186 def as_sqlite(self, compiler, connection, **extra_context): 

187 precision = self.get_source_expressions()[1] 

188 if isinstance(precision, Value) and precision.value < 0: 

189 raise ValueError("SQLite does not support negative precision.") 

190 return super().as_sqlite(compiler, connection, **extra_context) 

191 

192 def _resolve_output_field(self): 

193 source = self.get_source_expressions()[0] 

194 return source.output_field 

195 

196 

197class Sign(Transform): 

198 function = "SIGN" 

199 lookup_name = "sign" 

200 

201 

202class Sin(NumericOutputFieldMixin, Transform): 

203 function = "SIN" 

204 lookup_name = "sin" 

205 

206 

207class Sqrt(NumericOutputFieldMixin, Transform): 

208 function = "SQRT" 

209 lookup_name = "sqrt" 

210 

211 

212class Tan(NumericOutputFieldMixin, Transform): 

213 function = "TAN" 

214 lookup_name = "tan"