From d42dfeb2688927075c41d8e581b1bfda6148ee4f Mon Sep 17 00:00:00 2001 From: mdipierro Date: Sun, 30 Sep 2012 00:10:25 -0500 Subject: [PATCH] login works fine with lazy DAL --- VERSION | 2 +- applications/welcome/models/db.py | 2 +- gluon/dal.py | 108 +++++++++++++++++++++--------- gluon/storage.py | 2 +- gluon/tools.py | 2 +- 5 files changed, 79 insertions(+), 37 deletions(-) diff --git a/VERSION b/VERSION index f8baf1db..d9b1716d 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.0.9 (2012-09-29 23:47:22) dev +Version 2.0.9 (2012-09-30 00:10:18) dev diff --git a/applications/welcome/models/db.py b/applications/welcome/models/db.py index 26d28122..54a0b231 100644 --- a/applications/welcome/models/db.py +++ b/applications/welcome/models/db.py @@ -11,7 +11,7 @@ if not request.env.web2py_runtime_gae: ## if NOT running on Google App Engine use SQLite or other DB - db = DAL('sqlite://storage.sqlite') + db = DAL('sqlite://storage.sqlite') else: ## connect to Google BigTable (optional 'google:datastore://namespace') db = DAL('google:datastore') diff --git a/gluon/dal.py b/gluon/dal.py index 2415785d..bb2f4388 100644 --- a/gluon/dal.py +++ b/gluon/dal.py @@ -519,6 +519,8 @@ class ConnectionPool(object): sql_locker.release() if really: getattr(instance, 'close')() + if instance.db._singleton_code in thread_local.db_instances: + del thread_local.db_instances[instance.db._singleton_code] if callable(action): action(None) @@ -1945,7 +1947,7 @@ class BaseAdapter(ConnectionPool): db._referee_name % dict( table=rfield.tablename,field=rfield.name) if referee_link and not referee_link in colset: - colset[referee_link] = Set(db,rfield == id) + colset[referee_link] = LazySet(rfield,id) else: if not '_extra' in new_row: new_row['_extra'] = Row() @@ -6443,15 +6445,6 @@ class Row(object): del d[k] return d -def Row_unpickler(data): - return Row(cPickle.loads(data)) - -def Row_pickler(data): - return Row_unpickler, (cPickle.dumps(data.as_dict(datetime_to_str=False)),) - -copy_reg.pickle(Row, Row_pickler, Row_unpickler) - - ################################################################################ # Everything below should be independent of the specifics of the database # and should work for RDBMs and some NoSQL databases @@ -6583,15 +6576,23 @@ class DAL(object): Field('fieldname2')) """ - #def __new__(cls, uri, *args, **kwargs): - # if not hasattr(thread_local,'db_instances'): - # thread_local.db_instances = {} - # try: - # return thread_local.db_instances[uri] - # except KeyError: - # instance = super(DAL, cls).__new__(cls, uri, *args, **kwargs) - # thread_local.db_instances[uri] = instance - # return instance + def __new__(cls, uri='sqlite://dummy.db', *args, **kwargs): + if not hasattr(thread_local,'db_instances'): + thread_local.db_instances = {} + if 'singleton_code' in kwargs: + singleton_code = kwargs['singleton_code'] + del kwargs['singleton_code'] + else: + singleton_code = hashlib.md5(uri).hexdigest() + try: + db = thread_local.db_instances[singleton_code] + if args or kwargs: + raise RuntimeError, 'Cannot duplicate a Singleton' + except KeyError: + db = super(DAL, cls).__new__(cls, uri, *args, **kwargs) + db._singleton_code = singleton_code + thread_local.db_instances[singleton_code] = db + return db @staticmethod def set_folder(folder): @@ -6673,6 +6674,8 @@ class DAL(object): :attempts (defaults to 5). Number of times to attempt connecting """ + if hasattr(self,'_adapter'): return + if not decode_credentials: credential_decoder = lambda cred: cred else: @@ -7136,6 +7139,8 @@ def index(): adapter = self._adapter if adapter in thread_local.instances: thread_local.instances.remove(adapter) + if self._singleton_code in thread_local.db_instances: + del thread_local.db_instances[self._singleton_code] adapter.close() def executesql(self, query, placeholders=None, as_dict=False, @@ -7265,6 +7270,14 @@ def index(): self[tablename].import_from_csv_file( ifile, id_map, null, unique, id_offset, *args, **kwargs) +def DAL_unpickler(uri): + return DAL(uri) + +def DAL_pickler(db): + return DAL_unpickler, (db._uri,) + +copy_reg.pickle(DAL, DAL_pickler, DAL_unpickler) + class SQLALL(object): """ Helper class providing a comma-separated string having all the field names @@ -8825,10 +8838,12 @@ class Set(object): class RecordUpdater(object): def __init__(self, colset, table, id): - self.colset, self.table, self.id = colset, table, id + self.colset, self.db, self.tablename, self.id = \ + colset, table._db, table._tablename, id def __call__(self, **fields): - colset, table, id = self.colset, self.table, self.id + colset, db, tablename, id = self.colset, self.db, self.tablename, self.id + table = db[tablename] newfields = fields or dict(colset) for fieldname in newfields.keys(): if not fieldname in table.fields or table[fieldname].type=='id': @@ -8839,10 +8854,47 @@ class RecordUpdater(object): class RecordDeleter(object): def __init__(self, table, id): - self.table, self.id = table,id + self.db, self.tablename, self.id = table._db, table._tablename, id def __call__(self): - return self.table._db(self.table._id==self.id).delete() + return self.db(self.db[self.tablename]._id==self.id).delete() +class LazySet(object): + def __init__(self, field, id): + self.db, self.tablename, self.fieldname, self.id = \ + field.db, field._tablename, field.name, id + def _getset(self): + query = self.db[self.tablename][self.fieldname]==self.id + return Set(self.db,query) + def __repr__(self): + return repr(self._getset()) + def __call__(self, query, ignore_common_filters=False): + return self._getset()(query, ignore_common_filters) + def _count(self,distinct=None): + return self._getset()._count(distinct) + def _select(self, *fields, **attributes): + return self._getset()._select(*field,**attributes) + def _delete(self): + return self._getset()._delete() + def _update(self, **update_fields): + return self._getset()._update(**update_fields) + def isempty(self): + return self._getset().isempty() + def count(self,distinct=None, cache=None): + return self._getset().count(distinct,cache) + def select(self, *fields, **attributes): + return self._getset().select(*fields,**attributes) + def nested_select(self,*fields,**attributes): + return self._getset().nested_select(*fields,**attributes) + def delete(self): + return self._getset().delete() + def update(self, **update_fields): + return self._getset().update(**update_fields) + def update_naive(self, **update_fields): + return self._getset().update_naive(**update_fields) + def validate_and_update(self, **update_fields): + return self._getset().validate_and_update(**update_fields) + def delete_uploaded_files(self, upload_fields=None): + return self._getset().delete_uploaded_files(upload_fields) class VirtualCommand(object): def __init__(self,method,row): @@ -9218,16 +9270,6 @@ class Rows(object): import gluon.contrib.simplejson as simplejson return simplejson.dumps(items) -def Rows_unpickler(data): - return cPickle.loads(data) - -def Rows_pickler(data): - return Rows_unpickler, \ - (cPickle.dumps(data.as_list(storage_to_dict=False, - datetime_to_str=False)),) - -copy_reg.pickle(Rows, Rows_pickler, Rows_unpickler) - ################################################################################ # dummy function used to define some doctests diff --git a/gluon/storage.py b/gluon/storage.py index 081e7447..72750272 100644 --- a/gluon/storage.py +++ b/gluon/storage.py @@ -46,7 +46,7 @@ class Storage(dict): __repr__ = lambda self: '' % dict.__repr__(self) # http://stackoverflow.com/questions/5247250/why-does-pickle-getstate-accept-as-a-return-value-the-very-instance-it-requi __getstate__ = lambda self: None - __reduce_ex__ = None + # __reduce_ex__ = None def getlist(self,key): """ diff --git a/gluon/tools.py b/gluon/tools.py index d783e6d7..c465b83c 100644 --- a/gluon/tools.py +++ b/gluon/tools.py @@ -1709,7 +1709,7 @@ class Auth(object): """ login the user = db.auth_user(id) """ - # user=Storage(self.table_user()._filter_fields(user,id=True)) + user = Storage(self.table_user()._filter_fields(user,id=True)) current.session.auth = Storage( user = user, last_visit = current.request.now,