# -*- coding: utf-8 -*- import copy import marshal import struct import threading import time import traceback from .._compat import ( PY2, exists, copyreg, implements_bool, iterkeys, itervalues, iteritems, long ) from .._globals import THREAD_LOCAL from .serializers import serializers class cachedprop(object): #: a read-only @property that is only evaluated once. def __init__(self, fget, doc=None): self.fget = fget self.__doc__ = doc or fget.__doc__ self.__name__ = fget.__name__ def __get__(self, obj, cls): if obj is None: return self obj.__dict__[self.__name__] = result = self.fget(obj) return result @implements_bool class BasicStorage(object): def __init__(self, *args, **kwargs): return self.__dict__.__init__(*args, **kwargs) def __getitem__(self, key): return self.__dict__.__getitem__(str(key)) __setitem__ = object.__setattr__ def __delitem__(self, key): try: delattr(self, key) except AttributeError: raise KeyError(key) def __bool__(self): return len(self.__dict__) > 0 __iter__ = lambda self: self.__dict__.__iter__() __str__ = lambda self: self.__dict__.__str__() __repr__ = lambda self: self.__dict__.__repr__() has_key = __contains__ = lambda self, key: key in self.__dict__ def get(self, key, default=None): return self.__dict__.get(key, default) def update(self, *args, **kwargs): return self.__dict__.update(*args, **kwargs) def keys(self): return self.__dict__.keys() def iterkeys(self): return iterkeys(self.__dict__) def values(self): return self.__dict__.values() def itervalues(self): return itervalues(self.__dict__) def items(self): return self.__dict__.items() def iteritems(self): return iteritems(self.__dict__) pop = lambda self, *args, **kwargs: self.__dict__.pop(*args, **kwargs) clear = lambda self, *args, **kwargs: self.__dict__.clear(*args, **kwargs) copy = lambda self, *args, **kwargs: self.__dict__.copy(*args, **kwargs) def pickle_basicstorage(s): return BasicStorage, (dict(s),) copyreg.pickle(BasicStorage, pickle_basicstorage) class OpRow(object): __slots__ = ('_table', '_fields', '_values') def __init__(self, table): object.__setattr__(self, '_table', table) object.__setattr__(self, '_fields', {}) object.__setattr__(self, '_values', {}) def set_value(self, key, value, field=None): self._values[key] = value self._fields[key] = self._fields.get(key, field or self._table[key]) def del_value(self, key): del self._values[key] del self._fields[key] def __getitem__(self, key): return self._values[key] def __setitem__(self, key, value): return self.set_value(key, value) def __delitem__(self, key): return self.del_value(key) def __getattr__(self, key): try: return self[key] except KeyError: raise AttributeError def __setattr__(self, key, value): return self.set_value(key, value) def __delattr__(self, key): return self.del_value(key) def __iter__(self): return self._values.__iter__() def __contains__(self, key): return key in self._values def get(self, key, default=None): try: rv = self[key] except KeyError: rv = default return rv def keys(self): return self._values.keys() def iterkeys(self): return iterkeys(self._values) def values(self): return self._values.values() def itervalues(self): return itervalues(self._values) def items(self): return self._values.items() def iteritems(self): return iteritems(self._values) def op_values(self): return [ (self._fields[key], value) for key, value in iteritems(self._values) ] def __repr__(self): return '' % repr(self._values) class ConnectionConfigurationMixin(object): def _mock_reconnect(self): self._reconnect_lock = threading.RLock() self._connection_reconnect = self.reconnect self.reconnect = self._reconnect_and_configure self._reconnect_mocked = True def _reconnect_and_configure(self): self._connection_reconnect() with self._reconnect_lock: if self._reconnect_mocked: self._configure_on_first_reconnect() self.reconnect = self._connection_reconnect self._reconnect_mocked = False def _configure_on_first_reconnect(self): pass class Serializable(object): def as_dict(self, flat=False, sanitize=True): return self.__dict__ def as_xml(self, sanitize=True): return serializers.xml(self.as_dict(flat=True, sanitize=sanitize)) def as_json(self, sanitize=True): return serializers.json(self.as_dict(flat=True, sanitize=sanitize)) def as_yaml(self, sanitize=True): return serializers.yaml(self.as_dict(flat=True, sanitize=sanitize)) class Reference(long): def __allocate(self): if not self._record: self._record = self._table[long(self)] if not self._record: raise RuntimeError( "Using a recursive select but encountered a broken " + "reference: %s %d" % (self._table, long(self)) ) def __getattr__(self, key, default=None): if key == 'id': return long(self) if key in self._table: self.__allocate() if self._record: # to deal with case self.update_record() return self._record.get(key, default) else: return None def get(self, key, default=None): return self.__getattr__(key, default) def __setattr__(self, key, value): if key.startswith('_'): long.__setattr__(self, key, value) return self.__allocate() self._record[key] = value def __getitem__(self, key): if key == 'id': return long(self) self.__allocate() return self._record.get(key, None) def __setitem__(self, key, value): self.__allocate() self._record[key] = value def Reference_unpickler(data): return marshal.loads(data) def Reference_pickler(data): try: marshal_dump = marshal.dumps(long(data)) except AttributeError: marshal_dump = 'i%s' % struct.pack(' 0: data, self.p = self.data[self.p:i], i else: data, self.p = self.data[self.p:], len(self.data) return data def write(self, data): self.data += data def close_connection(self): if self.db is not None: self.db.executesql( "DELETE FROM web2py_filesystem WHERE path='%s'" % self.filename ) query = "INSERT INTO web2py_filesystem(path,content) VALUES ('%s','%s')"\ % (self.filename, self.data.replace("'", "''")) self.db.executesql(query) self.db.commit() self.db = None def close(self): self.close_connection() @staticmethod def is_operational_error(db, error): if not hasattr(db._adapter.driver, "OperationalError"): return None return isinstance(error, db._adapter.driver.OperationalError) @staticmethod def is_programming_error(db, error): if not hasattr(db._adapter.driver, "ProgrammingError"): return None return isinstance(error, db._adapter.driver.ProgrammingError) @staticmethod def exists(db, filename): if exists(filename): return True DatabaseStoredFile.try_create_web2py_filesystem(db) query = "SELECT path FROM web2py_filesystem WHERE path='%s'" % filename try: if db.executesql(query): return True except Exception as e: if not (DatabaseStoredFile.is_operational_error(db, e) or DatabaseStoredFile.is_programming_error(db, e)): raise # no web2py_filesystem found? tb = traceback.format_exc() db.logger.error("Could not retrieve %s\n%s" % (filename, tb)) return False