def create(import_defaults=True):
    """
    Create new Bauble database at the current connection

    :param import_defaults: A flag that is passed to each plugins
        install() method to indicate where it should import its
        default data.  This is mainly used for testing.  The default
        value is True
    :type import_defaults: bool

    """
    # TODO: when creating a database there shouldn't be any errors
    # on import since we are importing from the default values, we should
    # just force the import and send everything in the database at once
    # instead of using slices, this would make it alot faster but it may
    # make it more difficult to make the interface more responsive,
    # maybe we can use a dialog without the progress bar to show the status,
    # should probably work on the status bar to display this

    # TODO: we create a transaction here and the csv import creates another
    # nested transaction, we need to verify that if we rollback here then all
    # of the changes made by csv import are rolled back as well
##    debug('entered db.create()')
    if not engine:
        raise ValueError('engine is None, not connected to a database')
    import bauble
    import bauble.meta as meta
    import bauble.pluginmgr as pluginmgr
    import datetime

    connection = engine.connect()
    transaction = connection.begin()
    try:
        # TODO: here we are dropping/creating all the tables in the
        # metadata whether they are in the registry or not, we should
        # really only be creating those tables from registered
        # plugins, maybe with an uninstall() method on Plugin
        metadata.drop_all(bind=connection, checkfirst=True)
        metadata.create_all(bind=connection)

        # fill in the bauble meta table and install all the plugins
        meta_table = meta.BaubleMeta.__table__
        meta_table.insert(bind=connection).\
            execute(name=meta.VERSION_KEY,
                    value=unicode(bauble.version)).close()
        meta_table.insert(bind=connection).\
            execute(name=meta.CREATED_KEY,
                    value=unicode(datetime.datetime.now())).close()
    except GeneratorExit, e:
        # this is here in case the main windows is closed in the middle
        # of a task
        # UPDATE 2009.06.18: i'm not sure if this is still relevant since we
        # switched the task system to use fibra...but it doesn't hurt
        # having it here until we can make sure
        warning('bauble.db.create(): %s' % utils.utf8(e))
        transaction.rollback()
        raise
 def commit_changes(self):
     '''
     Commit the changes to self.session()
     '''
     objs = list(self.session)
     try:
         self.session.commit()
     except Exception, e:
         warning(e)
         self.session.rollback()
         self.session.add_all(objs)
         raise
def reset_sequence(column):
    """
    If column.sequence is not None or the column is an Integer and
    column.autoincrement is true then reset the sequence for the next
    available value for the column...if the column doesn't have a
    sequence then do nothing and return

    The SQL statements are executed directly from db.engine

    This function only works for PostgreSQL database.  It does nothing
    for other database engines.
    """
    import bauble
    import bauble.db as db
    from sqlalchemy.types import Integer
    from sqlalchemy import schema
    if not db.engine.name == 'postgresql':
        return

    sequence_name = None
    if hasattr(column,'default') and isinstance(column.default,schema.Sequence):
        sequence_name = column.default.name
    elif (isinstance(column.type, Integer) and column.autoincrement) and \
            (column.default is None or \
                 (isinstance(column.default, schema.Sequence) and \
                      column.default.optional)) and \
                      len(column.foreign_keys)==0:
        sequence_name = '%s_%s_seq' %(column.table.name, column.name)
    else:
        return
    conn = db.engine.connect()
    trans = conn.begin()
    try:
        # the FOR UPDATE locks the table for the transaction
        stmt = "SELECT %s from %s FOR UPDATE;" %(column.name, column.table.name)
        result = conn.execute(stmt)
        maxid = None
        vals = list(result)
        if vals:
            maxid = max(vals, key=lambda x: x[0])[0]
        result.close()
        if maxid == None:
            # set the sequence to nextval()
            stmt = "SELECT nextval('%s');" % (sequence_name)
        else:
            stmt = "SELECT setval('%s', max(%s)+1) from %s;" \
                % (sequence_name, column.name, column.table.name)
        conn.execute(stmt)
    except Exception, e:
        warning('bauble.utils.reset_sequence(): %s' % utf8(e))
        trans.rollback()
    def start(self):
        """
        Show the connection manager.
        """
        self.create_gui()
        self.dialog.connect('response', self.on_dialog_response)
        self.dialog.connect('close', self.on_dialog_close_or_delete)
        self.dialog.connect('delete-event', self.on_dialog_close_or_delete)
        conn_list = prefs[bauble.conn_list_pref]
        if conn_list is None or len(conn_list.keys()) == 0:
            msg = _('You don\'t have any connections in your connection '\
                    'list.\nClose this message and click on "Add" to create '\
                    'a new connection.')
            utils.message_dialog(msg)
        else:
            self.set_active_connection_by_name(self.default_name)
            self._dirty = False

        self._error = True
        name = None
        uri = None
        while name is None or self._error:
            response = self.dialog.run()
            if response == gtk.RESPONSE_OK:
                name = self._get_connection_name()
                uri = self._get_connection_uri()
                if name is None:
                    msg = _('You have to choose or create a new connection ' \
                            'before you can connect to the database.')
                    utils.message_dialog(msg)
            else:
                name = uri = None
                break

        # have to remove the cell_data_func to avoid a cyclical
        # reference which would cause the ConnectionManager to not get
        # garbage collected
        cell = self.type_combo.get_cells()[0]
        self.type_combo.set_cell_data_func(cell, None)
        self.type_combo.clear()
        self.name_combo.clear()

        # just to be sure let's destroy the dialog upfront and delete
        # the params box
        self.dialog.destroy()
        del self.params_box
        obj = utils.gc_objects_by_type(CMParamsBox)
        if obj:
            warning('ConnectionManager.start(): param box leaked: %s' % obj)
        return name, uri
    def cell_data_func(self, col, cell, model, treeiter):
        path = model.get_path(treeiter)
        tree_rect = self.results_view.get_visible_rect()
        cell_rect = self.results_view.get_cell_area(path, col)
        if cell_rect.y > tree_rect.height:
            # only update the cells if they're visible...this
            # drastically speeds up populating the view with large
            # datasets
            return
        value = model[treeiter][0]
        if isinstance(value, basestring):
            cell.set_property('markup', value)
        else:
            # if the value isn't part of a session then add it to the
            # view's session so that we can access its child
            # properties...this usually happens when one of the
            # ViewMeta's get_children() functions return a list of
            # object who's session was closed...we add it here for
            # performance reasons so we only add it onces its visible
            if not object_session(value):
                if value in self.session:
                    # expire the object in the session with the same key
                    self.session.expire(value)
                else:
                    self.session.add(value)
            try:
                func = self.view_meta[type(value)].markup_func
                if func is not None:
                    r = func(value)
                    if isinstance(r, (list,tuple)):
                        main, substr = r
                    else:
                        main = r
                        substr = '(%s)' % type(value).__name__
                else:
                    main = utils.xml_safe(str(value))
                    substr = '(%s)' % type(value).__name__
                cell.set_property('markup', '%s\n%s' % \
                                  (_mainstr_tmpl % utils.utf8(main),
                                   _substr_tmpl % utils.utf8(substr)))

            except (saexc.InvalidRequestError, TypeError), e:
                warning('bauble.view.SearchView.cell_data_func(): \n%s' % e)
                def remove():
                    model = self.results_view.get_model()
                    self.results_view.set_model(None) # detach model
                    for found in utils.search_tree_model(model, value):
                        model.remove(found)
                    self.results_view.set_model(model)
                gobject.idle_add(remove)
def _find_plugins(path):
    """
    Return the plugins at path.
    """
    plugins = []
    import bauble.plugins
    plugin_module = bauble.plugins
    errors = {}

    if path.find('library.zip') != -1:
        plugin_names = [m for m in _find_module_names(path) \
                        if m.startswith('bauble.plugins')]
    else:
        plugin_names =['bauble.plugins.%s'%m for m in _find_module_names(path)]

    for name in plugin_names:
        mod = None
        # Fast path: see if the module has already been imported.

        if name in sys.modules:
            mod = sys.modules[name]
        else:
            try:
                mod = __import__(name, globals(), locals(), [name], -1)
            except Exception, e:
                msg = _('Could not import the %(module)s module.\n\n'\
                        '%(error)s' % {'module': name, 'error': e})
                debug(msg)
                errors[name] = sys.exc_info()
        if not hasattr(mod, "plugin"):
            continue

        # if mod.plugin is a function it should return a plugin or list of
        # plugins
        try:
            mod_plugin = mod.plugin()
        except:
            mod_plugin = mod.plugin

        is_plugin = lambda p: isinstance(p, (type, types.ClassType)) and issubclass(p, Plugin)
        if isinstance(mod_plugin, (list, tuple)):
            for p in mod_plugin:
                if is_plugin(p) or True:
                    plugins.append(p)
        elif is_plugin(mod_plugin) or True:
            plugins.append(mod_plugin)
        else:
            warning(_('%s.plugin is not an instance of pluginmgr.Plugin'\
                      % mod.__name__))
 def on_activate(item, cb):
     result = False
     try:
         # have to get the selected values again here
         # because for some unknown reason using the
         # "selected" variable from the parent scope
         # will give us the objects but they won't be
         # in an session...maybe its a thread thing
         values = self.get_selected_values()
         result = cb(values)
     except Exception, e:
         msg = utils.xml_safe_utf8(str(e))
         tb = utils.xml_safe_utf8(traceback.format_exc())
         utils.message_details_dialog(msg, tb,gtk.MESSAGE_ERROR)
         warning(traceback.format_exc())
    def on_cursor_changed(self, view):
        '''
        Update the infobox and switch the accelerators depending on the
        type of the row that the cursor points to.
        '''
        self.update_infobox()
        self.update_notes()

        for accel, cb in self.installed_accels:
            # disconnect previously installed accelerators by the key
            # and modifier, accel_group.disconnect_by_func won't work
            # here since we install a closure as the actual callback
            # in instead of the original action.callback
            r = self.accel_group.disconnect_key(accel[0], accel[1])
            if not r:
                warning('callback not removed: %s' % cb)
        self.installed_accels = []

        selected = self.get_selected_values()
        if not selected:
            return
        selected_type = type(selected[0])

        for action in self.view_meta[selected_type].actions:
            enabled = (len(selected) > 1 and action.multiselect) or \
                (len(selected)<=1 and action.singleselect)
            if not enabled:
                continue
            # if enabled then connect the accelerator
            keyval, mod = gtk.accelerator_parse(action.accelerator)
            if (keyval, mod) != (0, 0):
                def cb(func):
                    def _impl(*args):
                        # getting the selected here allows the
                        # callback to be called on all the selected
                        # values and not just the value where the
                        # cursor is
                        sel = self.get_selected_values()
                        if func(sel):
                            self.reset_view()
                    return _impl
                self.accel_group.connect_group(keyval, mod,
                                               gtk.ACCEL_VISIBLE,
                                               cb(action.callback))
                self.installed_accels.append(((keyval, mod), action.callback))
            else:
                warning('Could not parse accelerator: %s' %(action.accelerator))
    def create_gui(self):
        if self.working_dbtypes is None or len(self.working_dbtypes) == 0:
            msg = _("No Python database connectors installed.\n"\
                    "Please consult the documentation for the "\
                    "prerequesites for installing Bauble.")
            utils.message_dialog(msg, gtk.MESSAGE_ERROR)
            raise Exception(msg)

        glade_path = os.path.join(paths.lib_dir(), "connmgr.glade")
        self.widgets = utils.BuilderWidgets(glade_path)

        self.dialog = self.widgets.main_dialog
        try:
            pixbuf = gtk.gdk.pixbuf_new_from_file(bauble.default_icon)
            self.dialog.set_icon(pixbuf)
        except Exception, e:
            warning(_('Could not load icon from %s' % bauble.default_icon))
            warning(traceback.format_exc())
    def _get_working_dbtypes(self, retry=False):
        """
        get for self.working_dbtypes property

        this sets self._working_dbtypes to a dictionary where the
        keys are the database names and the values are the index in
        the connectiona manager's database types
        """
        if self._working_dbtypes != [] and not retry:
            return self._working_dbtypes
        self._working_dbtypes = []
        try:
            try:
                import pysqlite2
            except Exception:
                import sqlite3
            self._working_dbtypes.append('SQLite')
        except ImportError, e:
            warning('ConnectionManager: %s' % e)
    def on_file_menu_open(self, widget, data=None):
        """
        Open the connection manager.
        """
        from connmgr import ConnectionManager
        default_conn = prefs[bauble.conn_default_pref]
        cm = ConnectionManager(default_conn)
        name, uri = cm.start()
        if name is None:
            return

        engine = None
        try:
            engine = db.open(uri, True, True)
        except Exception, e:
            # we don't do anything to handle the exception since
            # db.open() should have shown an error dialog if there was
            # a problem opening the database as long as the
            # show_error_dialogs parameter is True
            warning(e)
def _get_tagged_object_pairs(tag):
    """
    :param tag: a Tag instance
    """
    from bauble.view import SearchView
    kids = []
    for obj in tag._objects:
        try:
            # __import__ "from_list" parameters has to be a list of strings
            module_name, part, cls_name = str(obj.obj_class).rpartition('.')
            module = __import__(module_name, globals(), locals(),
                                module_name.split('.')[1:])
            cls = getattr(module, cls_name)
            kids.append((cls, obj.obj_id))
        except KeyError, e:
            warning('KeyError -- tag.get_tagged_objects(%s): %s' % (tag, e))
            continue
        except DBAPIError, e:
            warning('DBAPIError -- tag.get_tagged_objects(%s): %s' % (tag, e))
            continue
    def init(self):
        '''
        initialize the preferences, should only be called from app.main
        '''
        # create directory tree of filename if it doesn't yet exist
        head, tail = os.path.split(self._filename)
        if not os.path.exists(head):
            os.makedirs(head)

        self.config = RawConfigParser()

        # set the version if the file doesn't exist
        if not os.path.exists(self._filename):
            self[config_version_pref] = config_version
        else:
            self.config.read(self._filename)
        version = self[config_version_pref]
        if version is None:
            from bauble.utils.log import warning
            warning('%s has no config version pref' % self._filename)
            warning('setting the config version to %s.%s' % (config_version))
	    self[config_version_pref] = config_version

        # set some defaults if they don't exist
        if date_format_pref not in self:
            self[date_format_pref] = '%d-%m-%Y'
        if parse_dayfirst_pref not in self:
            format = self[date_format_pref]
            if format.find('%d') < format.find('%m'):
                self[parse_dayfirst_pref] = True
            else:
                self[parse_dayfirst_pref] = False
        if parse_yearfirst_pref not in self:
            format = self[date_format_pref]
            if format.find('%Y') == 0 or format.find('%y') == 0:
                self[parse_yearfirst_pref] = True
            else:
                self[parse_yearfirst_pref] = False

        if units_pref not in self:
            self[units_pref] = 'metric'
 from bauble.connmgr import ConnectionManager
 default_conn = prefs[conn_default_pref]
 while True:
     if not uri or not conn_name:
         cm = ConnectionManager(default_conn)
         conn_name, uri = cm.start()
         if conn_name is None:
             quit()
     try:
         if db.open(uri, True, True):
             prefs[conn_default_pref] = conn_name
             break
         else:
             uri = conn_name = None
     except err.VersionError, e:
         warning(e)
         db.open(uri, False)
         break
     except (err.EmptyDatabaseError, err.MetaTableError,
             err.VersionError, err.TimestampError,
             err.RegistryError), e:
         warning(e)
         open_exc = e
         # reopen without verification so that db.Session and
         # db.engine, db.metadata will be bound to an engine
         db.open(uri, False)
         break
     except err.DatabaseError, e:
         debug(e)
         #traceback.format_exc()
         open_exc = e
def install(plugins_to_install, import_defaults=True, force=False):
    """
    :param plugins_to_install: A list of plugins to install. If the
        string "all" is passed then install all plugins listed in the
        bauble.pluginmgr.plugins dict that aren't already listed in
        the plugin registry.

    :param import_defaults: Flag passed to the plugin's install()
        method to indicate whether it should import its default data.
    :type import_defaults: bool

    :param force:  Force, don't ask questions.
    :type force: book
    """
    #debug('pluginmgr.install(%s)' % plugins_to_install)
    if plugins_to_install is 'all':
        to_install = plugins.values()
    else:
        to_install = plugins_to_install

    if len(to_install) == 0:
        # no plugins to install
        return

    # sort the plugins by their dependency
    depends, unmet = _create_dependency_pairs(to_install)
    if unmet != {}:
        debug(unmet)
        raise BaubleError('unmet dependencies')
    to_install = utils.topological_sort(to_install, depends)
    if not to_install:
        raise BaubleError(_('The plugins contain a dependency loop. This '\
                            'can happend if two plugins directly or '\
                            'indirectly rely on each other'))

#         msg = _('The %(plugin)s plugin depends on the %(other_plugin)s '\
#                 'plugin but the %(other_plugin)s plugin wasn\'t found.') \
#                 % {'plugin': e.plugin.__name__, 'other_plugin': e.not_found}
#         utils.message_dialog(msg, gtk.MESSAGE_WARNING)

#         to_install = topological_sort(to_install, depends)
#     except DependencyError, e:
#         msg = _('The %(plugin)s plugin depends on the %(other_plugin)s '\
#                 'plugin but the %(other_plugin)s plugin wasn\'t found.') \
#                 % {'plugin': e.plugin.__name__, 'other_plugin': e.not_found}
#         utils.message_dialog(msg, gtk.MESSAGE_WARNING)
#         raise
#     except DependencyError, e:
#         error(utils.utf8(e))

    try:
        for p in to_install:
            #debug('install: %s' % p.__name__)
            p.install(import_defaults=import_defaults)
            # TODO: here we make sure we don't add the plugin to the
            # registry twice but we should really update the version
            # number in the future when we accept versioned plugins
            # (if ever)
            if not PluginRegistry.exists(p):
                PluginRegistry.add(p)
        #session.commit()
    except Exception, e:
        warning('bauble.pluginmgr.install(): %s' % utils.utf8(e))
        raise
                                'indirectly rely on each other'))

    # call init() for each ofthe plugins
    for plugin in ordered:
        #debug('init: %s' % plugin)
        try:
            plugin.init()
        except KeyError, e:
            # don't remove the plugin from the registry because if we
            # find it again the user might decide to reinstall it
            # which could overwrite data
            ordered.remove(plugin)
            msg = _("The %(plugin_name)s plugin is listed in the registry "\
                    "but isn't wasn't found in the plugin directory") \
                    % dict(plugin_name=plugin.__class__.__name__)
            warning(msg)
        except Exception, e:
            #error(e)
            ordered.remove(plugin)
            error(traceback.print_exc())
            safe = utils.xml_safe_utf8
            values = dict(entry_name=plugin.__class__.__name__, exception=safe(e))
            utils.message_details_dialog(_("Error: Couldn't initialize "\
                                           "%(entry_name)s\n\n" \
                                           "%(exception)s." % values),
                                         traceback.format_exc(),
                                         gtk.MESSAGE_ERROR)


    # register the plugin commands seperately from the plugin initialization
    for plugin in ordered:
    def __init__(self):
        filename = os.path.join(paths.lib_dir(), 'bauble.glade')
        self.widgets = utils.load_widgets(filename)
        self.window = self.widgets.main_window
        self.window.hide()

        # restore the window size
        geometry = prefs[self.window_geometry_pref]
        if geometry is not None:
            self.window.set_default_size(*geometry)

        self.window.connect('delete-event', self.on_delete_event)
        self.window.connect("destroy", self.on_quit)
        self.window.set_title(self.title)

        try:
            pixbuf = gtk.gdk.pixbuf_new_from_file(bauble.default_icon)
            self.window.set_icon(pixbuf)
        except Exception:
            warning(_('Could not load icon from %s' % bauble.default_icon))
            warning(traceback.format_exc())
            # utils.message_details_dialog(_('Could not load icon from %s' % \
            #                              bauble.default_icon),
            #                              traceback.format_exc(),
            #                              gtk.MESSAGE_ERROR)

        menubar = self.create_main_menu()
        self.widgets.menu_box.pack_start(menubar)

        combo = self.widgets.main_comboentry
        model = gtk.ListStore(str)
        combo.set_model(model)
        self.populate_main_entry()

        # disable: causes the entry contents to be selected on backspace
        #combo.connect('changed', lambda c: c.grab_focus())

        main_entry = combo.child
#        main_entry.connect('key_press_event', self.on_main_entry_key_press)
        main_entry.connect('activate', self.on_main_entry_activate)
        accel_group = gtk.AccelGroup()
        main_entry.add_accelerator("grab-focus", accel_group, ord('L'),
                                   gtk.gdk.CONTROL_MASK, gtk.ACCEL_VISIBLE)
        self.window.add_accel_group(accel_group)

        go_button = self.widgets.go_button
        go_button.connect('clicked', self.on_go_button_clicked)

        query_button = self.widgets.query_button
        query_button.connect('clicked', self.on_query_button_clicked)

        self.set_default_view()

        # add a progressbar to the status bar
        # Warning: this relies on gtk.Statusbar internals and could break in
        # future versions of gtk
        statusbar = self.widgets.statusbar
        statusbar.set_spacing(10)
        statusbar.set_has_resize_grip(True)
        self._cids = []
        def on_statusbar_push(sb, cid, txt):
            if cid not in self._cids:
                self._cids.append(cid)
        statusbar.connect('text-pushed', on_statusbar_push)

        # remove label from frame
        frame = statusbar.get_children()[0]
        #frame.modify_bg(gtk.STATE_NORMAL, gtk.gdk.color_parse('#FF0000'))
        label = frame.get_children()[0]
        frame.remove(label)

        # replace label with hbox and put label and progress bar in hbox
        hbox = gtk.HBox(False, 5)
        frame.add(hbox)
        hbox.pack_start(label, True, True, 0)
        vbox = gtk.VBox(True, 0)
        hbox.pack_end(vbox, False, True, 15)
        self.progressbar = gtk.ProgressBar()
        vbox.pack_start(self.progressbar, False, False, 0)
        self.progressbar.set_size_request(-1, 10)
        vbox.show()
        hbox.show()

        from pyparsing import StringStart, Word, alphanums, restOfLine, \
            StringEnd
        cmd = StringStart() +':'+ Word(alphanums + '-_').setResultsName('cmd')
        arg = restOfLine.setResultsName('arg')
        self.cmd_parser = (cmd + StringEnd()) | (cmd + '=' + arg) | arg

        combo.grab_focus()
            error('bauble.gui.on_insert_menu_item_activate():\n %s' \
                      % traceback.format_exc())
            return

        presenter_cls = view_cls = None
        if hasattr(editor, 'presenter'):
            presenter_cls = type(editor.presenter)
            view_cls = type(editor.presenter.view)

        # delete the editor
        del editor

        # check for leaks
        obj = utils.gc_objects_by_type(editor_cls)
        if obj != []:
            warning('%s leaked: %s' % (editor_cls.__name__, obj))

        if presenter_cls:
            obj = utils.gc_objects_by_type(presenter_cls)
            if obj != []:
                warning('%s leaked: %s' % (presenter_cls.__name__, obj))
            obj = utils.gc_objects_by_type(view_cls)
            if obj != []:
                warning('%s leaked: %s' % (view_cls.__name__, obj))


##     def on_edit_menu_prefs(self, widget, data=None):
##         p = PreferencesMgr()
##         p.run()
##         p.destroy()
    for obj in tag._objects:
        try:
            # __import__ "from_list" parameters has to be a list of strings
            module_name, part, cls_name = str(obj.obj_class).rpartition('.')
            module = __import__(module_name, globals(), locals(),
                                module_name.split('.')[1:])
            cls = getattr(module, cls_name)
            kids.append((cls, obj.obj_id))
        except KeyError, e:
            warning('KeyError -- tag.get_tagged_objects(%s): %s' % (tag, e))
            continue
        except DBAPIError, e:
            warning('DBAPIError -- tag.get_tagged_objects(%s): %s' % (tag, e))
            continue
        except AttributeError, e:
            warning('AttributeError -- tag.get_tagged_objects(%s): %s' \
                    % (tag, e))
            warning('Could not get the object for %s.%s(%s)' % \
                    (module_name, cls_name, obj.obj_id))
            continue

    return kids


def get_tagged_objects(tag, session=None):
    """
    Return all object tagged with tag.

    :param tag: A string or :class:`Tag`
    :param session:
    """
    close_session = False
            execute(name=meta.VERSION_KEY,
                    value=unicode(bauble.version)).close()
        meta_table.insert(bind=connection).\
            execute(name=meta.CREATED_KEY,
                    value=unicode(datetime.datetime.now())).close()
    except GeneratorExit, e:
        # this is here in case the main windows is closed in the middle
        # of a task
        # UPDATE 2009.06.18: i'm not sure if this is still relevant since we
        # switched the task system to use fibra...but it doesn't hurt
        # having it here until we can make sure
        warning('bauble.db.create(): %s' % utils.utf8(e))
        transaction.rollback()
        raise
    except Exception, e:
        warning('bauble.db.create(): %s' % utils.utf8(e))
        transaction.rollback()
        raise
    else:
        transaction.commit()
    finally:
        connection.close()

    connection = engine.connect()
    transaction = connection.begin()
    try:
        pluginmgr.install('all', import_defaults, force=True)
    except GeneratorExit, e:
        # this is here in case the main windows is closed in the middle
        # of a task
        # UPDATE 2009.06.18: i'm not sure if this is still relevant since we