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
« 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
8import re
10from .types import _StringType
11from ... import exc
12from ... import sql
13from ... import util
14from ...sql import sqltypes
15from ...sql.base import NO_ARG
18class ENUM(sqltypes.NativeForEmulated, sqltypes.Enum, _StringType):
19 """MySQL ENUM type."""
21 __visit_name__ = "ENUM"
23 native_enum = True
25 def __init__(self, *enums, **kw):
26 """Construct an ENUM.
28 E.g.::
30 Column('myenum', ENUM("foo", "bar", "baz"))
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.
37 .. versionadded: 1.1 added support for PEP-435-compliant enumerated
38 types.
40 :param strict: This flag has no effect.
42 .. versionchanged:: The MySQL ENUM type as well as the base Enum
43 type now validates all Python data values.
45 :param charset: Optional, a column-level character set for this string
46 value. Takes precedence to 'ascii' or 'unicode' short-hand.
48 :param collation: Optional, a column-level collation for this string
49 value. Takes precedence to 'binary' short-hand.
51 :param ascii: Defaults to False: short-hand for the ``latin1``
52 character set, generates ASCII in schema.
54 :param unicode: Defaults to False: short-hand for the ``ucs2``
55 character set, generates UNICODE in schema.
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.
62 :param quoting: Not used. A warning will be raised if provided.
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)
75 @classmethod
76 def adapt_emulated_to_native(cls, impl, **kw):
77 """Produce a MySQL native :class:`.mysql.ENUM` from plain
78 :class:`.Enum`.
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)
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)
96 def __repr__(self):
97 return util.generic_repr(
98 self, to_inspect=[ENUM, _StringType, sqltypes.Enum]
99 )
102class SET(_StringType):
103 """MySQL SET type."""
105 __visit_name__ = "SET"
107 def __init__(self, *values, **kw):
108 """Construct a SET.
110 E.g.::
112 Column('myset', SET("foo", "bar", "baz"))
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.
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.
123 :param convert_unicode: Same flag as that of
124 :paramref:`.String.convert_unicode`.
126 :param collation: same as that of :paramref:`.String.collation`
128 :param charset: same as that of :paramref:`.VARCHAR.charset`.
130 :param ascii: same as that of :paramref:`.VARCHAR.ascii`.
132 :param unicode: same as that of :paramref:`.VARCHAR.unicode`.
134 :param binary: same as that of :paramref:`.VARCHAR.binary`.
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.
146 .. warning::
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.
152 .. versionadded:: 1.0.0
154 :param quoting: Not used. A warning will be raised if passed.
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)
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
189 def result_processor(self, dialect, coltype):
190 if self.retrieve_as_bitwise:
192 def process(value):
193 if value is not None:
194 value = int(value)
196 return set(util.map_bits(self._bitmap.__getitem__, value))
197 else:
198 return None
200 else:
201 super_convert = super(SET, self).result_processor(dialect, coltype)
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
216 return process
218 def bind_processor(self, dialect):
219 super_convert = super(SET, self).bind_processor(dialect)
220 if self.retrieve_as_bitwise:
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
236 else:
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)
245 if super_convert:
246 return super_convert(value)
247 else:
248 return value
250 return process
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)
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 )