mirror of https://github.com/sgoudham/Enso-Bot.git
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
686 lines
23 KiB
Python
686 lines
23 KiB
Python
# Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights reserved.
|
|
#
|
|
# This program is free software; you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License, version 2.0, as
|
|
# published by the Free Software Foundation.
|
|
#
|
|
# This program is also distributed with certain software (including
|
|
# but not limited to OpenSSL) that is licensed under separate terms,
|
|
# as designated in a particular file or component or in included license
|
|
# documentation. The authors of MySQL hereby grant you an
|
|
# additional permission to link the program and your derivative works
|
|
# with the separately licensed software that they have included with
|
|
# MySQL.
|
|
#
|
|
# Without limiting anything contained in the foregoing, this file,
|
|
# which is part of MySQL Connector/Python, is also subject to the
|
|
# Universal FOSS Exception, version 1.0, a copy of which can be found at
|
|
# http://oss.oracle.com/licenses/universal-foss-exception.
|
|
#
|
|
# This program is distributed in the hope that it will be useful, but
|
|
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
# See the GNU General Public License, version 2.0, for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program; if not, write to the Free Software Foundation, Inc.,
|
|
# 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
"""Converting MySQL and Python types
|
|
"""
|
|
|
|
import datetime
|
|
import time
|
|
from decimal import Decimal
|
|
|
|
from .constants import FieldType, FieldFlag, CharacterSet
|
|
from .catch23 import PY2, NUMERIC_TYPES, struct_unpack
|
|
from .custom_types import HexLiteral
|
|
|
|
CONVERT_ERROR = "Could not convert '{value}' to python {pytype}"
|
|
|
|
|
|
class MySQLConverterBase(object):
|
|
"""Base class for conversion classes
|
|
|
|
All class dealing with converting to and from MySQL data types must
|
|
be a subclass of this class.
|
|
"""
|
|
|
|
def __init__(self, charset='utf8', use_unicode=True):
|
|
self.python_types = None
|
|
self.mysql_types = None
|
|
self.charset = None
|
|
self.charset_id = 0
|
|
self.use_unicode = None
|
|
self.set_charset(charset)
|
|
self.set_unicode(use_unicode)
|
|
self._cache_field_types = {}
|
|
|
|
def set_charset(self, charset):
|
|
"""Set character set"""
|
|
if charset == 'utf8mb4':
|
|
charset = 'utf8'
|
|
if charset is not None:
|
|
self.charset = charset
|
|
else:
|
|
# default to utf8
|
|
self.charset = 'utf8'
|
|
self.charset_id = CharacterSet.get_charset_info(self.charset)[0]
|
|
|
|
def set_unicode(self, value=True):
|
|
"""Set whether to use Unicode"""
|
|
self.use_unicode = value
|
|
|
|
def to_mysql(self, value):
|
|
"""Convert Python data type to MySQL"""
|
|
type_name = value.__class__.__name__.lower()
|
|
try:
|
|
return getattr(self, "_{0}_to_mysql".format(type_name))(value)
|
|
except AttributeError:
|
|
return value
|
|
|
|
def to_python(self, vtype, value):
|
|
"""Convert MySQL data type to Python"""
|
|
|
|
if (value == b'\x00' or value is None) and vtype[1] != FieldType.BIT:
|
|
# Don't go further when we hit a NULL value
|
|
return None
|
|
|
|
if not self._cache_field_types:
|
|
self._cache_field_types = {}
|
|
for name, info in FieldType.desc.items():
|
|
try:
|
|
self._cache_field_types[info[0]] = getattr(
|
|
self, '_{0}_to_python'.format(name))
|
|
except AttributeError:
|
|
# We ignore field types which has no method
|
|
pass
|
|
|
|
try:
|
|
return self._cache_field_types[vtype[1]](value, vtype)
|
|
except KeyError:
|
|
return value
|
|
|
|
def escape(self, value):
|
|
"""Escape buffer for sending to MySQL"""
|
|
return value
|
|
|
|
def quote(self, buf):
|
|
"""Quote buffer for sending to MySQL"""
|
|
return str(buf)
|
|
|
|
|
|
class MySQLConverter(MySQLConverterBase):
|
|
"""Default conversion class for MySQL Connector/Python.
|
|
|
|
o escape method: for escaping values send to MySQL
|
|
o quoting method: for quoting values send to MySQL in statements
|
|
o conversion mapping: maps Python and MySQL data types to
|
|
function for converting them.
|
|
|
|
Whenever one needs to convert values differently, a converter_class
|
|
argument can be given while instantiating a new connection like
|
|
cnx.connect(converter_class=CustomMySQLConverterClass).
|
|
|
|
"""
|
|
|
|
def __init__(self, charset=None, use_unicode=True):
|
|
MySQLConverterBase.__init__(self, charset, use_unicode)
|
|
self._cache_field_types = {}
|
|
|
|
def escape(self, value):
|
|
"""
|
|
Escapes special characters as they are expected to by when MySQL
|
|
receives them.
|
|
As found in MySQL source mysys/charset.c
|
|
|
|
Returns the value if not a string, or the escaped string.
|
|
"""
|
|
if value is None:
|
|
return value
|
|
elif isinstance(value, NUMERIC_TYPES):
|
|
return value
|
|
if isinstance(value, (bytes, bytearray)):
|
|
value = value.replace(b'\\', b'\\\\')
|
|
value = value.replace(b'\n', b'\\n')
|
|
value = value.replace(b'\r', b'\\r')
|
|
value = value.replace(b'\047', b'\134\047') # single quotes
|
|
value = value.replace(b'\042', b'\134\042') # double quotes
|
|
value = value.replace(b'\032', b'\134\032') # for Win32
|
|
else:
|
|
value = value.replace('\\', '\\\\')
|
|
value = value.replace('\n', '\\n')
|
|
value = value.replace('\r', '\\r')
|
|
value = value.replace('\047', '\134\047') # single quotes
|
|
value = value.replace('\042', '\134\042') # double quotes
|
|
value = value.replace('\032', '\134\032') # for Win32
|
|
return value
|
|
|
|
def quote(self, buf):
|
|
"""
|
|
Quote the parameters for commands. General rules:
|
|
o numbers are returns as bytes using ascii codec
|
|
o None is returned as bytearray(b'NULL')
|
|
o Everything else is single quoted '<buf>'
|
|
|
|
Returns a bytearray object.
|
|
"""
|
|
if isinstance(buf, NUMERIC_TYPES):
|
|
if PY2:
|
|
if isinstance(buf, float):
|
|
return repr(buf)
|
|
return str(buf)
|
|
return str(buf).encode('ascii')
|
|
elif isinstance(buf, type(None)):
|
|
return bytearray(b"NULL")
|
|
return bytearray(b"'" + buf + b"'")
|
|
|
|
def to_mysql(self, value):
|
|
"""Convert Python data type to MySQL"""
|
|
type_name = value.__class__.__name__.lower()
|
|
try:
|
|
return getattr(self, "_{0}_to_mysql".format(type_name))(value)
|
|
except AttributeError:
|
|
raise TypeError("Python '{0}' cannot be converted to a "
|
|
"MySQL type".format(type_name))
|
|
|
|
def to_python(self, vtype, value):
|
|
"""Convert MySQL data type to Python"""
|
|
if value == 0 and vtype[1] != FieldType.BIT: # \x00
|
|
# Don't go further when we hit a NULL value
|
|
return None
|
|
if value is None:
|
|
return None
|
|
|
|
if not self._cache_field_types:
|
|
self._cache_field_types = {}
|
|
for name, info in FieldType.desc.items():
|
|
try:
|
|
self._cache_field_types[info[0]] = getattr(
|
|
self, '_{0}_to_python'.format(name))
|
|
except AttributeError:
|
|
# We ignore field types which has no method
|
|
pass
|
|
|
|
try:
|
|
return self._cache_field_types[vtype[1]](value, vtype)
|
|
except KeyError:
|
|
# If one type is not defined, we just return the value as str
|
|
try:
|
|
return value.decode('utf-8')
|
|
except UnicodeDecodeError:
|
|
return value
|
|
except ValueError as err:
|
|
raise ValueError("%s (field %s)" % (err, vtype[0]))
|
|
except TypeError as err:
|
|
raise TypeError("%s (field %s)" % (err, vtype[0]))
|
|
except:
|
|
raise
|
|
|
|
def _int_to_mysql(self, value):
|
|
"""Convert value to int"""
|
|
return int(value)
|
|
|
|
def _long_to_mysql(self, value):
|
|
"""Convert value to int"""
|
|
return int(value)
|
|
|
|
def _float_to_mysql(self, value):
|
|
"""Convert value to float"""
|
|
return float(value)
|
|
|
|
def _str_to_mysql(self, value):
|
|
"""Convert value to string"""
|
|
if PY2:
|
|
return str(value)
|
|
return self._unicode_to_mysql(value)
|
|
|
|
def _unicode_to_mysql(self, value):
|
|
"""Convert unicode"""
|
|
charset = self.charset
|
|
charset_id = self.charset_id
|
|
if charset == 'binary':
|
|
charset = 'utf8'
|
|
charset_id = CharacterSet.get_charset_info(charset)[0]
|
|
encoded = value.encode(charset)
|
|
if charset_id in CharacterSet.slash_charsets:
|
|
if b'\x5c' in encoded:
|
|
return HexLiteral(value, charset)
|
|
return encoded
|
|
|
|
def _bytes_to_mysql(self, value):
|
|
"""Convert value to bytes"""
|
|
return value
|
|
|
|
def _bytearray_to_mysql(self, value):
|
|
"""Convert value to bytes"""
|
|
return bytes(value)
|
|
|
|
def _bool_to_mysql(self, value):
|
|
"""Convert value to boolean"""
|
|
if value:
|
|
return 1
|
|
return 0
|
|
|
|
def _nonetype_to_mysql(self, value):
|
|
"""
|
|
This would return what None would be in MySQL, but instead we
|
|
leave it None and return it right away. The actual conversion
|
|
from None to NULL happens in the quoting functionality.
|
|
|
|
Return None.
|
|
"""
|
|
return None
|
|
|
|
def _datetime_to_mysql(self, value):
|
|
"""
|
|
Converts a datetime instance to a string suitable for MySQL.
|
|
The returned string has format: %Y-%m-%d %H:%M:%S[.%f]
|
|
|
|
If the instance isn't a datetime.datetime type, it return None.
|
|
|
|
Returns a bytes.
|
|
"""
|
|
if value.microsecond:
|
|
fmt = '{0:d}-{1:02d}-{2:02d} {3:02d}:{4:02d}:{5:02d}.{6:06d}'
|
|
return fmt.format(
|
|
value.year, value.month, value.day,
|
|
value.hour, value.minute, value.second,
|
|
value.microsecond).encode('ascii')
|
|
|
|
fmt = '{0:d}-{1:02d}-{2:02d} {3:02d}:{4:02d}:{5:02d}'
|
|
return fmt.format(
|
|
value.year, value.month, value.day,
|
|
value.hour, value.minute, value.second).encode('ascii')
|
|
|
|
def _date_to_mysql(self, value):
|
|
"""
|
|
Converts a date instance to a string suitable for MySQL.
|
|
The returned string has format: %Y-%m-%d
|
|
|
|
If the instance isn't a datetime.date type, it return None.
|
|
|
|
Returns a bytes.
|
|
"""
|
|
return '{0:d}-{1:02d}-{2:02d}'.format(value.year, value.month,
|
|
value.day).encode('ascii')
|
|
|
|
def _time_to_mysql(self, value):
|
|
"""
|
|
Converts a time instance to a string suitable for MySQL.
|
|
The returned string has format: %H:%M:%S[.%f]
|
|
|
|
If the instance isn't a datetime.time type, it return None.
|
|
|
|
Returns a bytes.
|
|
"""
|
|
if value.microsecond:
|
|
return value.strftime('%H:%M:%S.%f').encode('ascii')
|
|
return value.strftime('%H:%M:%S').encode('ascii')
|
|
|
|
def _struct_time_to_mysql(self, value):
|
|
"""
|
|
Converts a time.struct_time sequence to a string suitable
|
|
for MySQL.
|
|
The returned string has format: %Y-%m-%d %H:%M:%S
|
|
|
|
Returns a bytes or None when not valid.
|
|
"""
|
|
return time.strftime('%Y-%m-%d %H:%M:%S', value).encode('ascii')
|
|
|
|
def _timedelta_to_mysql(self, value):
|
|
"""
|
|
Converts a timedelta instance to a string suitable for MySQL.
|
|
The returned string has format: %H:%M:%S
|
|
|
|
Returns a bytes.
|
|
"""
|
|
seconds = abs(value.days * 86400 + value.seconds)
|
|
|
|
if value.microseconds:
|
|
fmt = '{0:02d}:{1:02d}:{2:02d}.{3:06d}'
|
|
if value.days < 0:
|
|
mcs = 1000000 - value.microseconds
|
|
seconds -= 1
|
|
else:
|
|
mcs = value.microseconds
|
|
else:
|
|
fmt = '{0:02d}:{1:02d}:{2:02d}'
|
|
|
|
if value.days < 0:
|
|
fmt = '-' + fmt
|
|
|
|
(hours, remainder) = divmod(seconds, 3600)
|
|
(mins, secs) = divmod(remainder, 60)
|
|
|
|
if value.microseconds:
|
|
result = fmt.format(hours, mins, secs, mcs)
|
|
else:
|
|
result = fmt.format(hours, mins, secs)
|
|
|
|
if PY2:
|
|
return result
|
|
return result.encode('ascii')
|
|
|
|
def _decimal_to_mysql(self, value):
|
|
"""
|
|
Converts a decimal.Decimal instance to a string suitable for
|
|
MySQL.
|
|
|
|
Returns a bytes or None when not valid.
|
|
"""
|
|
if isinstance(value, Decimal):
|
|
return str(value).encode('ascii')
|
|
|
|
return None
|
|
|
|
def row_to_python(self, row, fields):
|
|
"""Convert a MySQL text result row to Python types
|
|
|
|
The row argument is a sequence containing text result returned
|
|
by a MySQL server. Each value of the row is converted to the
|
|
using the field type information in the fields argument.
|
|
|
|
Returns a tuple.
|
|
"""
|
|
i = 0
|
|
result = [None]*len(fields)
|
|
|
|
if not self._cache_field_types:
|
|
self._cache_field_types = {}
|
|
for name, info in FieldType.desc.items():
|
|
try:
|
|
self._cache_field_types[info[0]] = getattr(
|
|
self, '_{0}_to_python'.format(name))
|
|
except AttributeError:
|
|
# We ignore field types which has no method
|
|
pass
|
|
|
|
for field in fields:
|
|
field_type = field[1]
|
|
|
|
if (row[i] == 0 and field_type != FieldType.BIT) or row[i] is None:
|
|
# Don't convert NULL value
|
|
i += 1
|
|
continue
|
|
|
|
try:
|
|
result[i] = self._cache_field_types[field_type](row[i], field)
|
|
except KeyError:
|
|
# If one type is not defined, we just return the value as str
|
|
try:
|
|
result[i] = row[i].decode('utf-8')
|
|
except UnicodeDecodeError:
|
|
result[i] = row[i]
|
|
except (ValueError, TypeError) as err:
|
|
err.message = "{0} (field {1})".format(str(err), field[0])
|
|
raise
|
|
|
|
i += 1
|
|
|
|
return tuple(result)
|
|
|
|
def _FLOAT_to_python(self, value, desc=None): # pylint: disable=C0103
|
|
"""
|
|
Returns value as float type.
|
|
"""
|
|
return float(value)
|
|
|
|
_DOUBLE_to_python = _FLOAT_to_python
|
|
|
|
def _INT_to_python(self, value, desc=None): # pylint: disable=C0103
|
|
"""
|
|
Returns value as int type.
|
|
"""
|
|
return int(value)
|
|
|
|
_TINY_to_python = _INT_to_python
|
|
_SHORT_to_python = _INT_to_python
|
|
_INT24_to_python = _INT_to_python
|
|
_LONG_to_python = _INT_to_python
|
|
_LONGLONG_to_python = _INT_to_python
|
|
|
|
def _DECIMAL_to_python(self, value, desc=None): # pylint: disable=C0103
|
|
"""
|
|
Returns value as a decimal.Decimal.
|
|
"""
|
|
val = value.decode(self.charset)
|
|
return Decimal(val)
|
|
|
|
_NEWDECIMAL_to_python = _DECIMAL_to_python
|
|
|
|
def _str(self, value, desc=None):
|
|
"""
|
|
Returns value as str type.
|
|
"""
|
|
return str(value)
|
|
|
|
def _BIT_to_python(self, value, dsc=None): # pylint: disable=C0103
|
|
"""Returns BIT columntype as integer"""
|
|
int_val = value
|
|
if len(int_val) < 8:
|
|
int_val = b'\x00' * (8 - len(int_val)) + int_val
|
|
return struct_unpack('>Q', int_val)[0]
|
|
|
|
def _DATE_to_python(self, value, dsc=None): # pylint: disable=C0103
|
|
"""Converts TIME column MySQL to a python datetime.datetime type.
|
|
|
|
Raises ValueError if the value can not be converted.
|
|
|
|
Returns DATE column type as datetime.date type.
|
|
"""
|
|
if isinstance(value, datetime.date):
|
|
return value
|
|
try:
|
|
parts = value.split(b'-')
|
|
if len(parts) != 3:
|
|
raise ValueError("invalid datetime format: {} len: {}"
|
|
"".format(parts, len(parts)))
|
|
try:
|
|
return datetime.date(int(parts[0]), int(parts[1]), int(parts[2]))
|
|
except ValueError:
|
|
return None
|
|
except (IndexError, ValueError):
|
|
raise ValueError(
|
|
"Could not convert {0} to python datetime.timedelta".format(
|
|
value))
|
|
|
|
_NEWDATE_to_python = _DATE_to_python
|
|
|
|
def _TIME_to_python(self, value, dsc=None): # pylint: disable=C0103
|
|
"""Converts TIME column value to python datetime.time value type.
|
|
|
|
Converts the TIME column MySQL type passed as bytes to a python
|
|
datetime.datetime type.
|
|
|
|
Raises ValueError if the value can not be converted.
|
|
|
|
Returns datetime.time type.
|
|
"""
|
|
try:
|
|
(hms, mcs) = value.split(b'.')
|
|
mcs = int(mcs.ljust(6, b'0'))
|
|
except (TypeError, ValueError):
|
|
hms = value
|
|
mcs = 0
|
|
try:
|
|
(hours, mins, secs) = [int(d) for d in hms.split(b':')]
|
|
if value[0] == 45 or value[0] == '-': # if PY3 or PY2
|
|
mins, secs, mcs = -mins, -secs, -mcs
|
|
return datetime.timedelta(hours=hours, minutes=mins,
|
|
seconds=secs, microseconds=mcs)
|
|
except (IndexError, TypeError, ValueError):
|
|
raise ValueError(CONVERT_ERROR.format(value=value,
|
|
pytype="datetime.timedelta"))
|
|
|
|
def _DATETIME_to_python(self, value, dsc=None): # pylint: disable=C0103
|
|
""""Converts DATETIME column value to python datetime.time value type.
|
|
|
|
Converts the DATETIME column MySQL type passed as bytes to a python
|
|
datetime.datetime type.
|
|
|
|
Returns: datetime.datetime type.
|
|
"""
|
|
if isinstance(value, datetime.datetime):
|
|
return value
|
|
datetime_val = None
|
|
try:
|
|
(date_, time_) = value.split(b' ')
|
|
if len(time_) > 8:
|
|
(hms, mcs) = time_.split(b'.')
|
|
mcs = int(mcs.ljust(6, b'0'))
|
|
else:
|
|
hms = time_
|
|
mcs = 0
|
|
dtval = [int(i) for i in date_.split(b'-')] + \
|
|
[int(i) for i in hms.split(b':')] + [mcs, ]
|
|
if len(dtval) < 6:
|
|
raise ValueError("invalid datetime format: {} len: {}"
|
|
"".format(dtval, len(dtval)))
|
|
else:
|
|
# Note that by default MySQL accepts invalid timestamps
|
|
# (this is also backward compatibility).
|
|
# Traditionaly C/py returns None for this well formed but
|
|
# invalid datetime for python like '0000-00-00 HH:MM:SS'.
|
|
try:
|
|
datetime_val = datetime.datetime(*dtval)
|
|
except ValueError:
|
|
return None
|
|
except (IndexError, TypeError):
|
|
raise ValueError(CONVERT_ERROR.format(value=value,
|
|
pytype="datetime.timedelta"))
|
|
|
|
return datetime_val
|
|
|
|
_TIMESTAMP_to_python = _DATETIME_to_python
|
|
|
|
def _YEAR_to_python(self, value, desc=None): # pylint: disable=C0103
|
|
"""Returns YEAR column type as integer"""
|
|
try:
|
|
year = int(value)
|
|
except ValueError:
|
|
raise ValueError("Failed converting YEAR to int (%s)" % value)
|
|
|
|
return year
|
|
|
|
def _SET_to_python(self, value, dsc=None): # pylint: disable=C0103
|
|
"""Returns SET column type as set
|
|
|
|
Actually, MySQL protocol sees a SET as a string type field. So this
|
|
code isn't called directly, but used by STRING_to_python() method.
|
|
|
|
Returns SET column type as a set.
|
|
"""
|
|
set_type = None
|
|
val = value.decode(self.charset)
|
|
if not val:
|
|
return set()
|
|
try:
|
|
set_type = set(val.split(','))
|
|
except ValueError:
|
|
raise ValueError("Could not convert set %s to a sequence." % value)
|
|
return set_type
|
|
|
|
def _JSON_to_python(self, value, dsc=None): # pylint: disable=C0103
|
|
"""Returns JSON column type as python type
|
|
|
|
Returns JSON column type as python type.
|
|
"""
|
|
try:
|
|
num = float(value)
|
|
if num.is_integer():
|
|
return int(value)
|
|
return num
|
|
except ValueError:
|
|
pass
|
|
|
|
if value == b'true':
|
|
return True
|
|
elif value == b'false':
|
|
return False
|
|
|
|
# The following types are returned between double quotes or
|
|
# bytearray(b'"')[0] or int 34 for shortness.
|
|
if value[0] == 34 and value[-1] == 34:
|
|
value_nq = value[1:-1]
|
|
|
|
try:
|
|
value_datetime = self._DATETIME_to_python(value_nq)
|
|
if value_datetime is not None:
|
|
return value_datetime
|
|
except ValueError:
|
|
pass
|
|
try:
|
|
value_date = self._DATE_to_python(value_nq)
|
|
if value_date is not None:
|
|
return value_date
|
|
except ValueError:
|
|
pass
|
|
try:
|
|
value_time = self._TIME_to_python(value_nq)
|
|
if value_time is not None:
|
|
return value_time
|
|
except ValueError:
|
|
pass
|
|
|
|
if isinstance(value, (bytes, bytearray)):
|
|
return value.decode(self.charset)
|
|
|
|
if dsc is not None:
|
|
# Check if we deal with a SET
|
|
if dsc[7] & FieldFlag.SET:
|
|
return self._SET_to_python(value, dsc)
|
|
if dsc[7] & FieldFlag.BINARY:
|
|
if self.charset != 'binary' and not isinstance(value, str):
|
|
try:
|
|
return value.decode(self.charset)
|
|
except (LookupError, UnicodeDecodeError):
|
|
return value
|
|
else:
|
|
return value
|
|
|
|
return self._STRING_to_python(value, dsc)
|
|
|
|
def _STRING_to_python(self, value, dsc=None): # pylint: disable=C0103
|
|
"""
|
|
Note that a SET is a string too, but using the FieldFlag we can see
|
|
whether we have to split it.
|
|
|
|
Returns string typed columns as string type.
|
|
"""
|
|
if dsc is not None:
|
|
# Check if we deal with a SET
|
|
if dsc[7] & FieldFlag.SET:
|
|
return self._SET_to_python(value, dsc)
|
|
if dsc[7] & FieldFlag.BINARY:
|
|
if self.charset != 'binary' and not isinstance(value, str):
|
|
try:
|
|
return value.decode(self.charset)
|
|
except (LookupError, UnicodeDecodeError):
|
|
return value
|
|
else:
|
|
return value
|
|
|
|
if self.charset == 'binary':
|
|
return value
|
|
if isinstance(value, (bytes, bytearray)) and self.use_unicode:
|
|
return value.decode(self.charset)
|
|
|
|
return value
|
|
|
|
_VAR_STRING_to_python = _STRING_to_python
|
|
|
|
def _BLOB_to_python(self, value, dsc=None): # pylint: disable=C0103
|
|
"""Convert BLOB data type to Python"""
|
|
if not value:
|
|
# This is an empty BLOB
|
|
return ""
|
|
# JSON Values are stored in LONG BLOB, but the blob values recived
|
|
# from the server are not dilutable, check for JSON values.
|
|
return self._JSON_to_python(value, dsc)
|
|
|
|
_LONG_BLOB_to_python = _BLOB_to_python
|
|
_MEDIUM_BLOB_to_python = _BLOB_to_python
|
|
_TINY_BLOB_to_python = _BLOB_to_python
|