Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/sqlalchemy/dialects/mysql/enumerated.py: 26%

90 statements  

« prev     ^ index     » next       coverage.py v7.0.1, created at 2022-12-25 06:11 +0000

1# mysql/enumerated.py 

2# Copyright (C) 2005-2022 the SQLAlchemy authors and contributors 

3# <see AUTHORS file> 

4# 

5# This module is part of SQLAlchemy and is released under 

6# the MIT License: https://www.opensource.org/licenses/mit-license.php 

7 

8import re 

9 

10from .types import _StringType 

11from ... import exc 

12from ... import sql 

13from ... import util 

14from ...sql import sqltypes 

15from ...sql.base import NO_ARG 

16 

17 

18class ENUM(sqltypes.NativeForEmulated, sqltypes.Enum, _StringType): 

19 """MySQL ENUM type.""" 

20 

21 __visit_name__ = "ENUM" 

22 

23 native_enum = True 

24 

25 def __init__(self, *enums, **kw): 

26 """Construct an ENUM. 

27 

28 E.g.:: 

29 

30 Column('myenum', ENUM("foo", "bar", "baz")) 

31 

32 :param enums: The range of valid values for this ENUM. Values in 

33 enums are not quoted, they will be escaped and surrounded by single 

34 quotes when generating the schema. This object may also be a 

35 PEP-435-compliant enumerated type. 

36 

37 .. versionadded: 1.1 added support for PEP-435-compliant enumerated 

38 types. 

39 

40 :param strict: This flag has no effect. 

41 

42 .. versionchanged:: The MySQL ENUM type as well as the base Enum 

43 type now validates all Python data values. 

44 

45 :param charset: Optional, a column-level character set for this string 

46 value. Takes precedence to 'ascii' or 'unicode' short-hand. 

47 

48 :param collation: Optional, a column-level collation for this string 

49 value. Takes precedence to 'binary' short-hand. 

50 

51 :param ascii: Defaults to False: short-hand for the ``latin1`` 

52 character set, generates ASCII in schema. 

53 

54 :param unicode: Defaults to False: short-hand for the ``ucs2`` 

55 character set, generates UNICODE in schema. 

56 

57 :param binary: Defaults to False: short-hand, pick the binary 

58 collation type that matches the column's character set. Generates 

59 BINARY in schema. This does not affect the type of data stored, 

60 only the collation of character data. 

61 

62 :param quoting: Not used. A warning will be raised if provided. 

63 

64 """ 

65 if kw.pop("quoting", NO_ARG) is not NO_ARG: 

66 util.warn_deprecated_20( 

67 "The 'quoting' parameter to :class:`.mysql.ENUM` is deprecated" 

68 " and will be removed in a future release. " 

69 "This parameter now has no effect." 

70 ) 

71 kw.pop("strict", None) 

72 self._enum_init(enums, kw) 

73 _StringType.__init__(self, length=self.length, **kw) 

74 

75 @classmethod 

76 def adapt_emulated_to_native(cls, impl, **kw): 

77 """Produce a MySQL native :class:`.mysql.ENUM` from plain 

78 :class:`.Enum`. 

79 

80 """ 

81 kw.setdefault("validate_strings", impl.validate_strings) 

82 kw.setdefault("values_callable", impl.values_callable) 

83 kw.setdefault("omit_aliases", impl._omit_aliases) 

84 return cls(**kw) 

85 

86 def _object_value_for_elem(self, elem): 

87 # mysql sends back a blank string for any value that 

88 # was persisted that was not in the enums; that is, it does no 

89 # validation on the incoming data, it "truncates" it to be 

90 # the blank string. Return it straight. 

91 if elem == "": 

92 return elem 

93 else: 

94 return super(ENUM, self)._object_value_for_elem(elem) 

95 

96 def __repr__(self): 

97 return util.generic_repr( 

98 self, to_inspect=[ENUM, _StringType, sqltypes.Enum] 

99 ) 

100 

101 

102class SET(_StringType): 

103 """MySQL SET type.""" 

104 

105 __visit_name__ = "SET" 

106 

107 def __init__(self, *values, **kw): 

108 """Construct a SET. 

109 

110 E.g.:: 

111 

112 Column('myset', SET("foo", "bar", "baz")) 

113 

114 

115 The list of potential values is required in the case that this 

116 set will be used to generate DDL for a table, or if the 

117 :paramref:`.SET.retrieve_as_bitwise` flag is set to True. 

118 

119 :param values: The range of valid values for this SET. The values 

120 are not quoted, they will be escaped and surrounded by single 

121 quotes when generating the schema. 

122 

123 :param convert_unicode: Same flag as that of 

124 :paramref:`.String.convert_unicode`. 

125 

126 :param collation: same as that of :paramref:`.String.collation` 

127 

128 :param charset: same as that of :paramref:`.VARCHAR.charset`. 

129 

130 :param ascii: same as that of :paramref:`.VARCHAR.ascii`. 

131 

132 :param unicode: same as that of :paramref:`.VARCHAR.unicode`. 

133 

134 :param binary: same as that of :paramref:`.VARCHAR.binary`. 

135 

136 :param retrieve_as_bitwise: if True, the data for the set type will be 

137 persisted and selected using an integer value, where a set is coerced 

138 into a bitwise mask for persistence. MySQL allows this mode which 

139 has the advantage of being able to store values unambiguously, 

140 such as the blank string ``''``. The datatype will appear 

141 as the expression ``col + 0`` in a SELECT statement, so that the 

142 value is coerced into an integer value in result sets. 

143 This flag is required if one wishes 

144 to persist a set that can store the blank string ``''`` as a value. 

145 

146 .. warning:: 

147 

148 When using :paramref:`.mysql.SET.retrieve_as_bitwise`, it is 

149 essential that the list of set values is expressed in the 

150 **exact same order** as exists on the MySQL database. 

151 

152 .. versionadded:: 1.0.0 

153 

154 :param quoting: Not used. A warning will be raised if passed. 

155 

156 """ 

157 if kw.pop("quoting", NO_ARG) is not NO_ARG: 

158 util.warn_deprecated_20( 

159 "The 'quoting' parameter to :class:`.mysql.SET` is deprecated" 

160 " and will be removed in a future release. " 

161 "This parameter now has no effect." 

162 ) 

163 self.retrieve_as_bitwise = kw.pop("retrieve_as_bitwise", False) 

164 self.values = tuple(values) 

165 if not self.retrieve_as_bitwise and "" in values: 

166 raise exc.ArgumentError( 

167 "Can't use the blank value '' in a SET without " 

168 "setting retrieve_as_bitwise=True" 

169 ) 

170 if self.retrieve_as_bitwise: 

171 self._bitmap = dict( 

172 (value, 2 ** idx) for idx, value in enumerate(self.values) 

173 ) 

174 self._bitmap.update( 

175 (2 ** idx, value) for idx, value in enumerate(self.values) 

176 ) 

177 length = max([len(v) for v in values] + [0]) 

178 kw.setdefault("length", length) 

179 super(SET, self).__init__(**kw) 

180 

181 def column_expression(self, colexpr): 

182 if self.retrieve_as_bitwise: 

183 return sql.type_coerce( 

184 sql.type_coerce(colexpr, sqltypes.Integer) + 0, self 

185 ) 

186 else: 

187 return colexpr 

188 

189 def result_processor(self, dialect, coltype): 

190 if self.retrieve_as_bitwise: 

191 

192 def process(value): 

193 if value is not None: 

194 value = int(value) 

195 

196 return set(util.map_bits(self._bitmap.__getitem__, value)) 

197 else: 

198 return None 

199 

200 else: 

201 super_convert = super(SET, self).result_processor(dialect, coltype) 

202 

203 def process(value): 

204 if isinstance(value, util.string_types): 

205 # MySQLdb returns a string, let's parse 

206 if super_convert: 

207 value = super_convert(value) 

208 return set(re.findall(r"[^,]+", value)) 

209 else: 

210 # mysql-connector-python does a naive 

211 # split(",") which throws in an empty string 

212 if value is not None: 

213 value.discard("") 

214 return value 

215 

216 return process 

217 

218 def bind_processor(self, dialect): 

219 super_convert = super(SET, self).bind_processor(dialect) 

220 if self.retrieve_as_bitwise: 

221 

222 def process(value): 

223 if value is None: 

224 return None 

225 elif isinstance(value, util.int_types + util.string_types): 

226 if super_convert: 

227 return super_convert(value) 

228 else: 

229 return value 

230 else: 

231 int_value = 0 

232 for v in value: 

233 int_value |= self._bitmap[v] 

234 return int_value 

235 

236 else: 

237 

238 def process(value): 

239 # accept strings and int (actually bitflag) values directly 

240 if value is not None and not isinstance( 

241 value, util.int_types + util.string_types 

242 ): 

243 value = ",".join(value) 

244 

245 if super_convert: 

246 return super_convert(value) 

247 else: 

248 return value 

249 

250 return process 

251 

252 def adapt(self, impltype, **kw): 

253 kw["retrieve_as_bitwise"] = self.retrieve_as_bitwise 

254 return util.constructor_copy(self, impltype, *self.values, **kw) 

255 

256 def __repr__(self): 

257 return util.generic_repr( 

258 self, 

259 to_inspect=[SET, _StringType], 

260 additional_kw=[ 

261 ("retrieve_as_bitwise", False), 

262 ], 

263 )