diff --git a/VERSION b/VERSION index 35d8d2f4..968fa96d 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -Version 2.1.0 (2012-10-13 14:36:14) dev +Version 2.1.0 (2012-10-14 16:40:34) dev diff --git a/gluon/custom_import.py b/gluon/custom_import.py index aaf5e42c..4ba79f26 100644 --- a/gluon/custom_import.py +++ b/gluon/custom_import.py @@ -13,7 +13,7 @@ NAIVE_IMPORTER = __builtin__.__import__ TRACK_CHANGES = False INVALID_MODULES = set(sys.modules.keys()).union(('','gluon','applications','custom_import')) -# backward compatibility API +# backward compatibility API def custom_import_install(): __builtin__.__import__ = custom_importer @@ -22,17 +22,14 @@ def track_changes(track=True): global TRACK_CHANGES TRACK_CHANGES = track -def is_tracking_changes(): +def is_tracking_changes(): return TRACK_CHANGES -class CustomImportException(ImportError): - pass - def custom_importer(name, globals=None, locals=None, fromlist=None, level=-1): """ The web2py custom importer. Like the standard Python importer but it tries to transform import statements as something like - "import applications.app_name.modules.x". + "import applications.app_name.modules.x". If the import failed, fall back on naive_importer """ @@ -46,8 +43,7 @@ def custom_importer(name, globals=None, locals=None, fromlist=None, level=-1): if hasattr(current,'request') \ and level<=0 \ and not name.split('.')[0] in INVALID_MODULES \ - and isinstance(globals, dict): - import_tb = None + and isinstance(globals, dict): try: items = current.request.folder.split(os.path.sep) if not items[-1]: items = items[:-1] @@ -56,26 +52,22 @@ def custom_importer(name, globals=None, locals=None, fromlist=None, level=-1): # import like "import x" or "import x.y" result = None for itemname in name.split("."): + new_mod = base_importer( + modules_prefix, globals,locals, [itemname], level) + try: + result = result or new_mod.__dict__[itemname] + except KeyError, e: + raise ImportError, 'Cannot import module %s' % str(e) modules_prefix += "." + itemname - base_importer( - modules_prefix, globals,locals, [], level) return result else: # import like "from x import a, b, ..." pname = modules_prefix + "." + name return base_importer(pname, globals, locals, fromlist, level) except ImportError, e1: - import_tb = sys.exc_info()[2] - try: - return NAIVE_IMPORTER(name,globals,locals,fromlist,level) - except ImportError, e3: - raise ImportError, e1, import_tb.tb_next # there an import error in the module + pass # the module does not exist except Exception, e2: raise e2 # there is an error in the module - finally: - if import_tb: - import_tb = None - return NAIVE_IMPORTER(name,globals,locals,fromlist,level) diff --git a/gluon/dal.py b/gluon/dal.py index 27f428f6..31e068c6 100644 --- a/gluon/dal.py +++ b/gluon/dal.py @@ -835,6 +835,9 @@ class BaseAdapter(ConnectionPool): # add to list of fields sql_fields[field_name] = dict( + length=field.length, + unique=field.unique, + notnull=field.notnull, sortable=sortable, type=str(field_type), sql=ftype) @@ -1645,25 +1648,25 @@ class BaseAdapter(ConnectionPool): return list(tables) def commit(self): - return self.connection.commit() + if self.connection: return self.connection.commit() def rollback(self): - return self.connection.rollback() + if self.connection: return self.connection.rollback() def close_connection(self): - return self.connection.close() + if self.connection: return self.connection.close() def distributed_transaction_begin(self, key): return def prepare(self, key): - self.connection.prepare() - + if self.connection: self.connection.prepare() + def commit_prepared(self, key): - self.connection.commit() + if self.connection: self.connection.commit() def rollback_prepared(self, key): - self.connection.rollback() + if self.connection: self.connection.rollback() def concat_add(self, table): return ', ADD ' @@ -1675,6 +1678,7 @@ class BaseAdapter(ConnectionPool): self.execute(query) def log_execute(self, *a, **b): + if not self.connection: return None command = a[0] if self.db._debug: LOGGER.debug('SQL: %s' % command) @@ -2035,7 +2039,7 @@ class BaseAdapter(ConnectionPool): ################################################################################### class SQLiteAdapter(BaseAdapter): - drivers = ('sqlite3','sqlite2') + drivers = ('sqlite2','sqlite3') can_select_for_update = None # support ourselves with BEGIN TRANSACTION @@ -2071,7 +2075,7 @@ class SQLiteAdapter(BaseAdapter): self.db = db self.dbengine = "sqlite" self.uri = uri - self.find_driver(adapter_args) + if do_connect: self.find_driver(adapter_args) self.pool_size = 0 self.folder = folder self.db_codec = db_codec @@ -2130,11 +2134,11 @@ class SpatiaLiteAdapter(SQLiteAdapter): def __init__(self, db, uri, pool_size=0, folder=None, db_codec ='UTF-8', credential_decoder=IDENTITY, driver_args={}, - adapter_args={}, srid=4326): + adapter_args={}, do_connect=True, srid=4326): self.db = db self.dbengine = "spatialite" self.uri = uri - self.find_driver(adapter_args) + if do_connect: self.find_driver(adapter_args) self.pool_size = 0 self.folder = folder self.db_codec = db_codec @@ -2239,7 +2243,7 @@ class JDBCSQLiteAdapter(SQLiteAdapter): self.db = db self.dbengine = "sqlite" self.uri = uri - self.find_driver(adapter_args) + if do_connect: self.find_driver(adapter_args) self.pool_size = pool_size self.folder = folder self.db_codec = db_codec @@ -2341,7 +2345,7 @@ class MySQLAdapter(BaseAdapter): self.db = db self.dbengine = "mysql" self.uri = uri - self.find_driver(adapter_args,uri) + if do_connect: self.find_driver(adapter_args,uri) self.pool_size = pool_size self.folder = folder self.db_codec = db_codec @@ -2467,7 +2471,7 @@ class PostgreSQLAdapter(BaseAdapter): self.db = db self.dbengine = "postgres" self.uri = uri - self.find_driver(adapter_args,uri) + if do_connect: self.find_driver(adapter_args,uri) self.pool_size = pool_size self.folder = folder self.db_codec = db_codec @@ -2693,7 +2697,7 @@ class JDBCPostgreSQLAdapter(PostgreSQLAdapter): self.db = db self.dbengine = "postgres" self.uri = uri - self.find_driver(adapter_args,uri) + if do_connect: self.find_driver(adapter_args,uri) self.pool_size = pool_size self.folder = folder self.db_codec = db_codec @@ -2818,7 +2822,7 @@ class OracleAdapter(BaseAdapter): self.db = db self.dbengine = "oracle" self.uri = uri - self.find_driver(adapter_args,uri) + if do_connect: self.find_driver(adapter_args,uri) self.pool_size = pool_size self.folder = folder self.db_codec = db_codec @@ -2974,7 +2978,7 @@ class MSSQLAdapter(BaseAdapter): self.db = db self.dbengine = "mssql" self.uri = uri - self.find_driver(adapter_args,uri) + if do_connect: self.find_driver(adapter_args,uri) self.pool_size = pool_size self.folder = folder self.db_codec = db_codec @@ -3171,7 +3175,7 @@ class SybaseAdapter(MSSQLAdapter): self.db = db self.dbengine = "sybase" self.uri = uri - self.find_driver(adapter_args,uri) + if do_connect: self.find_driver(adapter_args,uri) self.pool_size = pool_size self.folder = folder self.db_codec = db_codec @@ -3301,7 +3305,7 @@ class FireBirdAdapter(BaseAdapter): self.db = db self.dbengine = "firebird" self.uri = uri - self.find_driver(adapter_args,uri) + if do_connect: self.find_driver(adapter_args,uri) self.pool_size = pool_size self.folder = folder self.db_codec = db_codec @@ -3360,7 +3364,7 @@ class FireBirdEmbeddedAdapter(FireBirdAdapter): self.db = db self.dbengine = "firebird" self.uri = uri - self.find_driver(adapter_args,uri) + if do_connect: self.find_driver(adapter_args,uri) self.pool_size = pool_size self.folder = folder self.db_codec = db_codec @@ -3467,7 +3471,7 @@ class InformixAdapter(BaseAdapter): self.db = db self.dbengine = "informix" self.uri = uri - self.find_driver(adapter_args,uri) + if do_connect: self.find_driver(adapter_args,uri) self.pool_size = pool_size self.folder = folder self.db_codec = db_codec @@ -3569,7 +3573,7 @@ class DB2Adapter(BaseAdapter): self.db = db self.dbengine = "db2" self.uri = uri - self.find_driver(adapter_args,uri) + if do_connect: self.find_driver(adapter_args,uri) self.pool_size = pool_size self.folder = folder self.db_codec = db_codec @@ -3632,7 +3636,7 @@ class TeradataAdapter(BaseAdapter): self.db = db self.dbengine = "teradata" self.uri = uri - self.find_driver(adapter_args,uri) + if do_connect: self.find_driver(adapter_args,uri) self.pool_size = pool_size self.folder = folder self.db_codec = db_codec @@ -3713,7 +3717,7 @@ class IngresAdapter(BaseAdapter): self.db = db self.dbengine = "ingres" self.uri = uri - self.find_driver(adapter_args,uri) + if do_connect: self.find_driver(adapter_args,uri) self.pool_size = pool_size self.folder = folder self.db_codec = db_codec @@ -3849,7 +3853,7 @@ class SAPDBAdapter(BaseAdapter): self.db = db self.dbengine = "sapdb" self.uri = uri - self.find_driver(adapter_args,uri) + if do_connect: self.find_driver(adapter_args,uri) self.pool_size = pool_size self.folder = folder self.db_codec = db_codec @@ -3892,7 +3896,7 @@ class CubridAdapter(MySQLAdapter): self.db = db self.dbengine = "cubrid" self.uri = uri - self.find_driver(adapter_args,uri) + if do_connect: self.find_driver(adapter_args,uri) self.pool_size = pool_size self.folder = folder self.db_codec = db_codec @@ -4697,7 +4701,7 @@ class CouchDBAdapter(NoSQLAdapter): adapter_args={}, do_connect=True): self.db = db self.uri = uri - self.find_driver(adapter_args) + if do_connect: self.find_driver(adapter_args) self.dbengine = 'couchdb' self.folder = folder db['_lastsql'] = '' @@ -4858,7 +4862,7 @@ class MongoDBAdapter(NoSQLAdapter): adapter_args={}, do_connect=True): self.db = db self.uri = uri - self.find_driver(adapter_args) + if do_connect: self.find_driver(adapter_args) m=None try: @@ -5465,7 +5469,7 @@ class IMAPAdapter(NoSQLAdapter): self.db = db self.uri = uri - self.find_driver(adapter_args) + if do_connect: self.find_driver(adapter_args) self.pool_size=pool_size self.folder = folder self.db_codec = db_codec @@ -6673,7 +6677,7 @@ class DAL(object): decode_credentials=False, driver_args=None, adapter_args=None, attempts=5, auto_import=False, bigint_id=False,debug=False,lazy_tables=False, - db_uid=None): + db_uid=None, do_connect=True): """ Creates a new Database Abstraction Layer instance. @@ -6739,10 +6743,15 @@ class DAL(object): raise SyntaxError, "Error in URI '%s' or database not supported" % self._dbname # notice that driver args or {} else driver_args # defaults to {} global, not correct - args = (self,uri,pool_size,folder, - db_codec, credential_decoder, - driver_args or {}, adapter_args or {}) - self._adapter = ADAPTERS[self._dbname](*args) + kwargs = dict(db=self,uri=uri, + pool_size=pool_size, + folder=folder, + db_codec=db_codec, + credential_decoder=credential_decoder, + driver_args=driver_args or {}, + adapter_args=adapter_args or {}, + do_connect=do_connect) + self._adapter = ADAPTERS[self._dbname](**kwargs) if bigint_id: types = ADAPTERS[self._dbname].types self._adapter.types = copy.copy(types) # copy so multiple DAL() possible @@ -6763,8 +6772,9 @@ class DAL(object): if not connected: raise RuntimeError, "Failure to connect, tried %d times:\n%s" % (attempts, tb) else: - args = (self,'None',0,folder,db_codec) - self._adapter = BaseAdapter(*args) + self._adapter = BaseAdapter(db=self,pool_size=0, + uri='None',folder=folder, + db_codec=db_codec) migrate = fake_migrate = False adapter = self._adapter self._uri_hash = hashlib.md5(adapter.uri).hexdigest() @@ -6791,7 +6801,12 @@ class DAL(object): try: sql_fields = cPickle.load(tfile) name = filename[len(pattern)-7:-6] - mf = [(value['sortable'],Field(key,type=value['type'])) \ + mf = [(value['sortable'], + Field(key, + type=value['type'], + length=value.get('length',None), + notnull=value.get('notnull',False), + unique=value.get('unique',False))) \ for key, value in sql_fields.iteritems()] mf.sort(lambda a,b: cmp(a[0],b[0])) self.define_table(name,*[item[1] for item in mf], diff --git a/gluon/tools.py b/gluon/tools.py index 03838bcd..8023171b 100644 --- a/gluon/tools.py +++ b/gluon/tools.py @@ -1627,6 +1627,7 @@ class Auth(object): urlbase = settings.cas_provider, actions=actions, maps=maps) + return self def log_event(self, description, vars=None, origin='auth'): """ @@ -4603,7 +4604,7 @@ class Wiki(object): Field('can_edit', 'list:string', writable=perms,readable=perms, default=[Wiki.everybody]), - Field('changelog'), + Field('changelog'), Field('html','text',compute=render, readable=False, writable=False), auth.signature], @@ -4625,8 +4626,17 @@ class Wiki(object): # define only non-existent tables for key, value in table_definitions: + args = [] if not key in db.tables(): - db.define_table(key, *value['args'], **value['vars']) + # look for wiki_ extra fields in auth.settings + extra_fields = auth.settings.extra_fields + if extra_fields: + if key in extra_fields: + if extra_fields[key]: + for field in extra_fields[key]: + args.append(field) + args += value['args'] + db.define_table(key, *args, **value['vars']) def update_tags_insert(page,id,db=db): for tag in page.tags or []: @@ -4789,15 +4799,16 @@ class Wiki(object): $(function() { if (!$('#wiki_page_body').length) return; var pagecontent = $('#wiki_page_body'); + pagecontent.css('font-family', 'Monaco,Menlo,Consolas,"Courier New",monospace'); var prevbutton = $(''); var preview = $('
').hide(); var table = $('form'); prevbutton.insertBefore(table); + preview.insertBefore(table); prevbutton.on('click', function(e) { e.preventDefault(); if (prevbutton.hasClass('nopreview')) { prevbutton.addClass('preview').removeClass('nopreview').html('Edit Source'); - preview.insertBefore(table); web2py_ajax_page('post', '%(url)s', {body : $('#wiki_page_body').val()}, 'preview'); table.fadeOut('medium', function() {preview.fadeIn()}); } else {