Package web2py :: Package gluon :: Package contrib :: Package pymysql :: Module converters |
[hide private]
[frames] | no frames]

# Source Code for Module web2py.gluon.contrib.pymysql.converters

      1  import re
      2  import datetime
      3  import time
      4
      5  from constants import FIELD_TYPE, FLAG
      6  from charset import charset_by_id
      7
      8  try:
      9      set
     10  except NameError:
     11      try:
     12          from sets import BaseSet as set
     13      except ImportError:
     14          from sets import Set as set
     15
     16  ESCAPE_REGEX = re.compile(r"[\0\n\r\032\'\"\\]")
     17  ESCAPE_MAP = {'\0': '\\0', '\n': '\\n', '\r': '\\r', '\032': '\\Z',
     18                '\'': '\\\'', '"': '\\"', '\\': '\\\\'}
     19
     20 -def escape_item(val, charset):
     21      if type(val) in [tuple, list, set]:
     22          return escape_sequence(val, charset)
     23      if type(val) is dict:
     24          return escape_dict(val, charset)
     25      if hasattr(val, "decode") and not isinstance(val, unicode):
     26          # deal with py3k bytes
     27          val = val.decode(charset)
     28      encoder = encoders[type(val)]
     29      val = encoder(val)
     30      if type(val) is str:
     31          return val
     32      val = val.encode(charset)
     33      return val
     34
     35 -def escape_dict(val, charset):
     36      n = {}
     37      for k, v in val.items():
     38          quoted = escape_item(v, charset)
     39          n[k] = quoted
     40      return n
     41
     42 -def escape_sequence(val, charset):
     43      n = []
     44      for item in val:
     45          quoted = escape_item(item, charset)
     46          n.append(quoted)
     47      return tuple(n)
     48
     49 -def escape_set(val, charset):
     50      val = map(lambda x: escape_item(x, charset), val)
     51      return ','.join(val)
     52
     53 -def escape_bool(value):
     54      return str(int(value))
     55
     56 -def escape_object(value):
     57      return str(value)
     58
     59  escape_int = escape_long = escape_object
     60
     61 -def escape_float(value):
     62      return ('%.15g' % value)
     63
     64 -def escape_string(value):
     65      return ("'%s'" % ESCAPE_REGEX.sub(
     66              lambda match: ESCAPE_MAP.get(match.group(0)), value))
     67
     68 -def escape_unicode(value):
     69      return escape_string(value)
     70
     71 -def escape_None(value):
     72      return 'NULL'
     73
     74 -def escape_timedelta(obj):
     75      seconds = int(obj.seconds) % 60
     76      minutes = int(obj.seconds // 60) % 60
     77      hours = int(obj.seconds // 3600) % 24 + int(obj.days) * 24
     78      return escape_string('%02d:%02d:%02d' % (hours, minutes, seconds))
     79
     80 -def escape_time(obj):
     81      s = "%02d:%02d:%02d" % (int(obj.hour), int(obj.minute),
     82                              int(obj.second))
     83      if obj.microsecond:
     84          s += ".%f" % obj.microsecond
     85
     86      return escape_string(s)
     87
     88 -def escape_datetime(obj):
     89      return escape_string(obj.strftime("%Y-%m-%d %H:%M:%S"))
     90
     91 -def escape_date(obj):
     92      return escape_string(obj.strftime("%Y-%m-%d"))
     93
     94 -def escape_struct_time(obj):
     95      return escape_datetime(datetime.datetime(*obj[:6]))
     96
     97 -def convert_datetime(connection, field, obj):
     98      """Returns a DATETIME or TIMESTAMP column value as a datetime object:
     99
    100        >>> datetime_or_None('2007-02-25 23:06:20')
    101        datetime.datetime(2007, 2, 25, 23, 6, 20)
    102        >>> datetime_or_None('2007-02-25T23:06:20')
    103        datetime.datetime(2007, 2, 25, 23, 6, 20)
    104
    105      Illegal values are returned as None:
    106
    107        >>> datetime_or_None('2007-02-31T23:06:20') is None
    108        True
    109        >>> datetime_or_None('0000-00-00 00:00:00') is None
    110        True
    111
    112      """
    113      if not isinstance(obj, unicode):
    114          obj = obj.decode(connection.charset)
    115      if ' ' in obj:
    116          sep = ' '
    117      elif 'T' in obj:
    118          sep = 'T'
    119      else:
    120          return convert_date(connection, field, obj)
    121
    122      try:
    123          ymd, hms = obj.split(sep, 1)
    124          return datetime.datetime(*[ int(x) for x in ymd.split('-')+hms.split(':') ])
    125      except ValueError:
    126          return convert_date(connection, field, obj)
    127
    128 -def convert_timedelta(connection, field, obj):
    129      """Returns a TIME column as a timedelta object:
    130
    131        >>> timedelta_or_None('25:06:17')
    132        datetime.timedelta(1, 3977)
    133        >>> timedelta_or_None('-25:06:17')
    134        datetime.timedelta(-2, 83177)
    135
    136      Illegal values are returned as None:
    137
    138        >>> timedelta_or_None('random crap') is None
    139        True
    140
    141      Note that MySQL always returns TIME columns as (+|-)HH:MM:SS, but
    142      can accept values as (+|-)DD HH:MM:SS. The latter format will not
    143      be parsed correctly by this function.
    144      """
    145      from math import modf
    146      try:
    147          if not isinstance(obj, unicode):
    148              obj = obj.decode(connection.charset)
    149          hours, minutes, seconds = tuple([int(x) for x in obj.split(':')])
    150          tdelta = datetime.timedelta(
    151              hours = int(hours),
    152              minutes = int(minutes),
    153              seconds = int(seconds),
    154              microseconds = int(modf(float(seconds))[0]*1000000),
    155              )
    156          return tdelta
    157      except ValueError:
    158          return None
    159
    160 -def convert_time(connection, field, obj):
    161      """Returns a TIME column as a time object:
    162
    163        >>> time_or_None('15:06:17')
    164        datetime.time(15, 6, 17)
    165
    166      Illegal values are returned as None:
    167
    168        >>> time_or_None('-25:06:17') is None
    169        True
    170        >>> time_or_None('random crap') is None
    171        True
    172
    173      Note that MySQL always returns TIME columns as (+|-)HH:MM:SS, but
    174      can accept values as (+|-)DD HH:MM:SS. The latter format will not
    175      be parsed correctly by this function.
    176
    177      Also note that MySQL's TIME column corresponds more closely to
    178      Python's timedelta and not time. However if you want TIME columns
    179      to be treated as time-of-day and not a time offset, then you can
    180      use set this function as the converter for FIELD_TYPE.TIME.
    181      """
    182      from math import modf
    183      try:
    184          hour, minute, second = obj.split(':')
    185          return datetime.time(hour=int(hour), minute=int(minute),
    186                               second=int(second),
    187                               microsecond=int(modf(float(second))[0]*1000000))
    188      except ValueError:
    189          return None
    190
    191 -def convert_date(connection, field, obj):
    192      """Returns a DATE column as a date object:
    193
    194        >>> date_or_None('2007-02-26')
    195        datetime.date(2007, 2, 26)
    196
    197      Illegal values are returned as None:
    198
    199        >>> date_or_None('2007-02-31') is None
    200        True
    201        >>> date_or_None('0000-00-00') is None
    202        True
    203
    204      """
    205      try:
    206          if not isinstance(obj, unicode):
    207              obj = obj.decode(connection.charset)
    208          return datetime.date(*[ int(x) for x in obj.split('-', 2) ])
    209      except ValueError:
    210          return None
    211
    212 -def convert_mysql_timestamp(connection, field, timestamp):
    213      """Convert a MySQL TIMESTAMP to a Timestamp object.
    214
    215      MySQL >= 4.1 returns TIMESTAMP in the same format as DATETIME:
    216
    217        >>> mysql_timestamp_converter('2007-02-25 22:32:17')
    218        datetime.datetime(2007, 2, 25, 22, 32, 17)
    219
    220      MySQL < 4.1 uses a big string of numbers:
    221
    222        >>> mysql_timestamp_converter('20070225223217')
    223        datetime.datetime(2007, 2, 25, 22, 32, 17)
    224
    225      Illegal values are returned as None:
    226
    227        >>> mysql_timestamp_converter('2007-02-31 22:32:17') is None
    228        True
    229        >>> mysql_timestamp_converter('00000000000000') is None
    230        True
    231
    232      """
    233      if not isinstance(timestamp, unicode):
    234          timestamp = timestamp.decode(connection.charset)
    235
    236      if timestamp[4] == '-':
    237          return convert_datetime(connection, field, timestamp)
    238      timestamp += "0"*(14-len(timestamp)) # padding
    239      year, month, day, hour, minute, second = \
    240          int(timestamp[:4]), int(timestamp[4:6]), int(timestamp[6:8]), \
    241          int(timestamp[8:10]), int(timestamp[10:12]), int(timestamp[12:14])
    242      try:
    243          return datetime.datetime(year, month, day, hour, minute, second)
    244      except ValueError:
    245          return None
    246
    247 -def convert_set(s):
    248      return set(s.split(","))
    249
    250 -def convert_bit(connection, field, b):
    251      #b = "\x00" * (8 - len(b)) + b # pad w/ zeroes
    252      #return struct.unpack(">Q", b)[0]
    253      #
    254      # the snippet above is right, but MySQLdb doesn't process bits,
    255      # so we shouldn't either
    256      return b
    257
    258 -def convert_characters(connection, field, data):
    259      field_charset = charset_by_id(field.charsetnr).name
    260      if field.flags & FLAG.SET:
    261          return convert_set(data.decode(field_charset))
    262      if field.flags & FLAG.BINARY:
    263          return data
    264
    265      if connection.use_unicode:
    266          data = data.decode(field_charset)
    267      elif connection.charset != field_charset:
    268          data = data.decode(field_charset)
    269          data = data.encode(connection.charset)
    270      else:
    271          data = data.decode(connection.charset)
    272      return data
    273
    274 -def convert_int(connection, field, data):
    275      return int(data)
    276
    277 -def convert_long(connection, field, data):
    278      return long(data)
    279
    280 -def convert_float(connection, field, data):
    281      return float(data)
    282
    283  encoders = {
    284          bool: escape_bool,
    285          int: escape_int,
    286          long: escape_long,
    287          float: escape_float,
    288          str: escape_string,
    289          unicode: escape_unicode,
    290          tuple: escape_sequence,
    291          list:escape_sequence,
    292          set:escape_sequence,
    293          dict:escape_dict,
    294          type(None):escape_None,
    295          datetime.date: escape_date,
    296          datetime.datetime : escape_datetime,
    297          datetime.timedelta : escape_timedelta,
    298          datetime.time : escape_time,
    299          time.struct_time : escape_struct_time,
    300          }
    301
    302  decoders = {
    303          FIELD_TYPE.BIT: convert_bit,
    304          FIELD_TYPE.TINY: convert_int,
    305          FIELD_TYPE.SHORT: convert_int,
    306          FIELD_TYPE.LONG: convert_long,
    307          FIELD_TYPE.FLOAT: convert_float,
    308          FIELD_TYPE.DOUBLE: convert_float,
    309          FIELD_TYPE.DECIMAL: convert_float,
    310          FIELD_TYPE.NEWDECIMAL: convert_float,
    311          FIELD_TYPE.LONGLONG: convert_long,
    312          FIELD_TYPE.INT24: convert_int,
    313          FIELD_TYPE.YEAR: convert_int,
    314          FIELD_TYPE.TIMESTAMP: convert_mysql_timestamp,
    315          FIELD_TYPE.DATETIME: convert_datetime,
    316          FIELD_TYPE.TIME: convert_timedelta,
    317          FIELD_TYPE.DATE: convert_date,
    318          FIELD_TYPE.SET: convert_set,
    319          FIELD_TYPE.BLOB: convert_characters,
    320          FIELD_TYPE.TINY_BLOB: convert_characters,
    321          FIELD_TYPE.MEDIUM_BLOB: convert_characters,
    322          FIELD_TYPE.LONG_BLOB: convert_characters,
    323          FIELD_TYPE.STRING: convert_characters,
    324          FIELD_TYPE.VAR_STRING: convert_characters,
    325          FIELD_TYPE.VARCHAR: convert_characters,
    326          #FIELD_TYPE.BLOB: str,
    327          #FIELD_TYPE.STRING: str,
    328          #FIELD_TYPE.VAR_STRING: str,
    329          #FIELD_TYPE.VARCHAR: str
    330          }
    331  conversions = decoders  # for MySQLdb compatibility
    332
    333  try:
    334      # python version > 2.3
    335      from decimal import Decimal
    336 -    def convert_decimal(connection, field, data):
    337          return Decimal(data)
    338      decoders[FIELD_TYPE.DECIMAL] = convert_decimal
    339      decoders[FIELD_TYPE.NEWDECIMAL] = convert_decimal
    340
    341 -    def escape_decimal(obj):
    342          return unicode(obj)
    343      encoders[Decimal] = escape_decimal
    344
    345  except ImportError:
    346      pass
    347