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