import json from base64 import b64decode from datetime import datetime, date, time, timedelta from decimal import Decimal from .._compat import PY2, integer_types, basestring, to_bytes, to_native from ..adapters.base import SQLAdapter from ..helpers.classes import Reference from ..helpers.methods import bar_decode_string, bar_decode_integer from . import Parser, parsers, for_type, before_parse long = integer_types[-1] class BasicParser(Parser): @for_type('id') def _id(self, value): return long(value) @for_type('integer') def _integer(self, value): return long(value) @for_type('float') def _float(self, value): return float(value) @for_type('double') def _double(self, value): return self.registered['float'](value, 'double') @for_type('boolean') def _boolean(self, value): return value == self.dialect.true or str(value)[:1].lower() == 't' @for_type('blob') def _blob(self, value): decoded = b64decode(to_bytes(value)) try: decoded = to_native(decoded) except: pass return decoded @before_parse('reference') def reference_extras(self, field_type): return {'referee': field_type[10:].strip()} @for_type('reference') def _reference(self, value, referee): if '.' not in referee: value = Reference(value) value._table, value._record = self.adapter.db[referee], None return value @before_parse('list:reference') def referencelist_extras(self, field_type): return {'field_type': field_type} @for_type('list:reference') def _list_references(self, value, field_type): return [self.registered['reference']( el, field_type[5:]) for el in value] @for_type('bigint') def _bigint(self, value): return self.registered['integer'](value, 'bigint') class DateParser(Parser): @for_type('date') def _date(self, value): if isinstance(value, datetime): return value.date() (y, m, d) = map(int, str(value)[:10].strip().split('-')) return date(y, m, d) class TimeParser(Parser): @for_type('time') def _time(self, value): if isinstance(value, datetime): return value.time() time_items = list(map(int, str(value)[:8].strip().split(':')[:3])) if len(time_items) == 3: (h, mi, s) = time_items else: (h, mi, s) = time_items + [0] return time(h, mi, s) class DateTimeParser(Parser): @for_type('datetime') def _datetime(self, value): value = str(value) date_part, time_part, timezone = value[:10], value[11:19], value[19:] if '+' in timezone: ms, tz = timezone.split('+') h, m = tz.split(':') dt = timedelta(seconds=3600 * int(h) + 60 * int(m)) elif '-' in timezone: ms, tz = timezone.split('-') h, m = tz.split(':') dt = -timedelta(seconds=3600 * int(h) + 60 * int(m)) else: ms = timezone.upper().split('Z')[0] dt = None (y, m, d) = map(int, date_part.split('-')) time_parts = time_part and time_part.split(':')[:3] or (0, 0, 0) while len(time_parts) < 3: time_parts.append(0) time_items = map(int, time_parts) (h, mi, s) = time_items if ms and ms[0] == '.': ms = int(float('0' + ms) * 1000000) else: ms = 0 value = datetime(y, m, d, h, mi, s, ms) if dt: value = value + dt return value class DecimalParser(Parser): @for_type('decimal') def _decimal(self, value): return Decimal(value) class JSONParser(Parser): @for_type('json') def _json(self, value): #if 'loads' not in self.driver_auto_json: if not isinstance(value, basestring): raise RuntimeError('json data not a string') if PY2 and isinstance(value, unicode): value = value.encode('utf-8') return json.loads(value) class ListsParser(BasicParser): @for_type('list:integer') def _list_integers(self, value): return bar_decode_integer(value) @for_type('list:string') def _list_strings(self, value): return bar_decode_string(value) @for_type('list:reference') def _list_references(self, value, field_type): value = bar_decode_integer(value) return [self.registered['reference']( el, field_type[5:]) for el in value] @parsers.register_for(SQLAdapter) class Commonparser( ListsParser, DateParser, TimeParser, DateTimeParser, DecimalParser, JSONParser ): pass