RFC PT3: Bibles

This commit is contained in:
Jon Tibble 2010-06-15 01:44:06 +01:00
parent e71caf43e7
commit 554ab59caf
10 changed files with 151 additions and 198 deletions

View File

@ -74,13 +74,20 @@ class Manager(object):
"""
Provide generic object persistence management
"""
def __init__(self, plugin_name, init_schema):
def __init__(self, plugin_name, init_schema, db_file_name=None):
"""
Runs the initialisation process that includes creating the connection
to the database and the tables if they don't exist.
``plugin_name``
The name to setup paths and settings section names
``init_schema``
The init_schema function for this database
``db_file_name``
The file name to use for this database. Defaults to None resulting
in the plugin_name being used.
"""
settings = QtCore.QSettings()
settings.beginGroup(plugin_name)
@ -88,6 +95,11 @@ class Manager(object):
db_type = unicode(
settings.value(u'db type', QtCore.QVariant(u'sqlite')).toString())
if db_type == u'sqlite':
if db_file_name:
self.db_url = u'sqlite:///%s/%s' % (
AppLocation.get_section_data_path(plugin_name),
db_file_name)
else:
self.db_url = u'sqlite:///%s/%s.sqlite' % (
AppLocation.get_section_data_path(plugin_name), plugin_name)
else:
@ -99,6 +111,30 @@ class Manager(object):
settings.endGroup()
self.session = init_schema(self.db_url)
def delete_database(self, plugin_name, db_file_name=None):
"""
Remove a database file from the system.
``plugin_name``
The name of the plugin to remove the database for
``db_file_name``
The database file name. Defaults to None resulting in the
plugin_name being used.
"""
db_file_path = None
if db_file_name:
db_file_path = os.path.join(
AppLocation.get_section_data_path(plugin_name), db_file_name)
else:
db_file_path = os.path.join(
AppLocation.get_section_data_path(plugin_name), plugin_name)
try:
os.remove(db_file_path)
return True
except OSError:
return False
def insert_object(self, object_instance):
"""
Save an object to the database

View File

@ -239,10 +239,8 @@ class ImportWizardForm(QtGui.QWizard, Ui_BibleImportWizard):
"""
Show the file open dialog for the verses CSV file.
"""
self.getFileName(
translate(u'BiblesPlugin.ImportWizardForm',
u'Open Verses CSV File'),
self.CsvVerseLocationEdit)
self.getFileName(translate(u'BiblesPlugin.ImportWizardForm',
u'Open Verses CSV File'), self.CsvVerseLocationEdit)
def onOpenSongBrowseButtonClicked(self):
"""
@ -450,11 +448,11 @@ class ImportWizardForm(QtGui.QWizard, Ui_BibleImportWizard):
self.ImportProgressLabel.setText(
translate(u'BiblesPlugin.ImportWizardForm',
u'Your Bible import failed.'))
importer.delete()
importer.delete_database(self.bibleplugin.settingsSection,
importer.file)
def postImport(self):
self.ImportProgressBar.setValue(self.ImportProgressBar.maximum())
self.finishButton.setVisible(True)
self.cancelButton.setVisible(False)
Receiver.send_message(u'openlp_process_events')

View File

@ -97,11 +97,11 @@ class CSVBible(BibleDB):
book_ptr = book.name
self.wizard.incrementProgressBar(
u'Importing %s %s' % (book.name, line[1]))
self.commit()
self.session.commit()
self.create_verse(book.id, line[1], line[2],
unicode(line[3], details['encoding']))
Receiver.send_message(u'openlp_process_events')
self.commit()
self.session.commit()
except IOError:
log.exception(u'Loading verses from file failed')
success = False
@ -113,5 +113,3 @@ class CSVBible(BibleDB):
return False
else:
return success

View File

@ -23,19 +23,98 @@
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
import os
import logging
import chardet
import re
from sqlalchemy import or_
from PyQt4 import QtCore
from sqlalchemy import Column, ForeignKey, or_, Table, types
from sqlalchemy.orm import class_mapper, mapper, relation
from sqlalchemy.orm.exc import UnmappedClassError
from openlp.plugins.bibles.lib.models import *
from openlp.core.lib.db import BaseModel, init_db, Manager
log = logging.getLogger(__name__)
class BibleDB(QtCore.QObject):
class BibleMeta(BaseModel):
"""
Bible Meta Data
"""
pass
class Testament(BaseModel):
"""
Bible Testaments
"""
pass
class Book(BaseModel):
"""
Song model
"""
pass
class Verse(BaseModel):
"""
Topic model
"""
pass
def init_schema(url):
"""
Setup a bible database connection and initialise the database schema
``url``
The database to setup
"""
session, metadata = init_db(url)
meta_table = Table(u'metadata', metadata,
Column(u'key', types.Unicode(255), primary_key=True, index=True),
Column(u'value', types.Unicode(255)),
)
testament_table = Table(u'testament', metadata,
Column(u'id', types.Integer, primary_key=True),
Column(u'name', types.Unicode(50)),
)
book_table = Table(u'book', metadata,
Column(u'id', types.Integer, primary_key=True),
Column(u'testament_id', types.Integer, ForeignKey(u'testament.id')),
Column(u'name', types.Unicode(50), index=True),
Column(u'abbreviation', types.Unicode(5), index=True),
)
verse_table = Table(u'verse', metadata,
Column(u'id', types.Integer, primary_key=True, index=True),
Column(u'book_id', types.Integer, ForeignKey(u'book.id'), index=True),
Column(u'chapter', types.Integer, index=True),
Column(u'verse', types.Integer, index=True),
Column(u'text', types.UnicodeText, index=True),
)
try:
class_mapper(BibleMeta)
except UnmappedClassError:
mapper(BibleMeta, meta_table)
try:
class_mapper(Testament)
except UnmappedClassError:
mapper(Testament, testament_table,
properties={'books': relation(Book, backref='testament')})
try:
class_mapper(Book)
except UnmappedClassError:
mapper(Book, book_table,
properties={'verses': relation(Verse, backref='book')})
try:
class_mapper(Verse)
except UnmappedClassError:
mapper(Verse, verse_table)
metadata.create_all(checkfirst=True)
return session
class BibleDB(QtCore.QObject, Manager):
"""
This class represents a database-bound Bible. It is used as a base class
for all the custom importers, so that the can implement their own import
@ -72,24 +151,7 @@ class BibleDB(QtCore.QObject):
self.file = self.clean_filename(self.name)
if u'file' in kwargs:
self.file = kwargs[u'file']
self.db_file = os.path.join(kwargs[u'path'], self.file)
log.debug(u'Load bible %s on path %s', self.file, self.db_file)
settings = QtCore.QSettings()
settings.beginGroup(u'bibles')
db_type = unicode(
settings.value(u'db type', QtCore.QVariant(u'sqlite')).toString())
db_url = u''
if db_type == u'sqlite':
db_url = u'sqlite:///' + self.db_file
else:
db_url = u'%s://%s:%s@%s/%s' % (db_type,
unicode(settings.value(u'db username').toString()),
unicode(settings.value(u'db password').toString()),
unicode(settings.value(u'db hostname').toString()),
unicode(settings.value(u'db database').toString()))
settings.endGroup()
self.session = init_models(db_url)
metadata.create_all(checkfirst=True)
Manager.__init__(self, u'bibles', init_schema, self.file)
if u'file' in kwargs:
self.get_name()
@ -104,7 +166,7 @@ class BibleDB(QtCore.QObject):
"""
Returns the version name of the Bible.
"""
version_name = self.get_meta(u'Version')
version_name = self.get_object(BibleMeta, u'Version')
if version_name:
self.name = version_name.value
else:
@ -124,16 +186,6 @@ class BibleDB(QtCore.QObject):
old_filename = re.sub(r'[^\w]+', u'_', old_filename).strip(u'_')
return old_filename + u'.sqlite'
def delete(self):
"""
Remove the Bible database file. Used when a Bible import fails.
"""
try:
os.remove(self.db_file)
return True
except OSError:
return False
def register(self, wizard):
"""
This method basically just initialialises the database. It is called
@ -148,33 +200,15 @@ class BibleDB(QtCore.QObject):
self.create_tables()
return self.name
def commit(self):
"""
Perform a database commit.
"""
log.debug('Committing...')
self.session.commit()
def create_tables(self):
"""
Create some initial metadata.
"""
log.debug(u'createTables')
self.create_meta(u'dbversion', u'2')
self.create_testament(u'Old Testament')
self.create_testament(u'New Testament')
self.create_testament(u'Apocrypha')
def create_testament(self, testament):
"""
Add a testament to the database.
``testament``
The testament name.
"""
log.debug(u'BibleDB.create_testament("%s")', testament)
self.session.add(Testament.populate(name=testament))
self.commit()
self.insert_object(Testament.populate(name=u'Old Testament'))
self.insert_object(Testament.populate(name=u'New Testament'))
self.insert_object(Testament.populate(name=u'Apocrypha'))
def create_book(self, name, abbrev, testament=1):
"""
@ -192,8 +226,7 @@ class BibleDB(QtCore.QObject):
log.debug(u'create_book %s,%s', name, abbrev)
book = Book.populate(name=name, abbreviation=abbrev,
testament_id=testament)
self.session.add(book)
self.commit()
self.insert_object(book)
return book
def create_chapter(self, book_id, chapter, textlist):
@ -220,7 +253,7 @@ class BibleDB(QtCore.QObject):
text = verse_text
)
self.session.add(verse)
self.commit()
self.session.commit()
def create_verse(self, book_id, chapter, verse, text):
"""
@ -252,12 +285,7 @@ class BibleDB(QtCore.QObject):
def create_meta(self, key, value):
log.debug(u'save_meta %s/%s', key, value)
self.session.add(BibleMeta.populate(key=key, value=value))
self.commit()
def get_books(self):
log.debug(u'BibleDB.get_books()')
return self.session.query(Book).order_by(Book.id).all()
self.insert_object(BibleMeta.populate(key=key, value=value))
def get_book(self, book):
log.debug(u'BibleDb.get_book("%s")', book)
@ -362,19 +390,6 @@ class BibleDB(QtCore.QObject):
else:
return count
def get_meta(self, key):
log.debug(u'get meta %s', key)
return self.session.query(BibleMeta).get(key)
def delete_meta(self, metakey):
biblemeta = self.get_meta(metakey)
try:
self.session.delete(biblemeta)
self.commit()
return True
except:
return False
def dump_bible(self):
log.debug(u'.........Dumping Bible Database')
log.debug('...............................Books ')
@ -383,4 +398,3 @@ class BibleDB(QtCore.QObject):
log.debug(u'...............................Verses ')
verses = self.session.query(Verse).all()
log.debug(verses)

View File

@ -35,8 +35,7 @@ from openlp.core.lib import Receiver
from openlp.core.utils import AppLocation
from openlp.plugins.bibles.lib.common import BibleCommon, SearchResults, \
unescape
from openlp.plugins.bibles.lib.db import BibleDB
from openlp.plugins.bibles.lib.models import Book
from openlp.plugins.bibles.lib.db import BibleDB, Book
log = logging.getLogger(__name__)

View File

@ -29,12 +29,12 @@ from PyQt4 import QtCore
from openlp.core.lib import SettingsManager
from openlp.core.utils import AppLocation
from openlp.plugins.bibles.lib.db import BibleDB, Book, BibleMeta
from common import parse_reference
from opensong import OpenSongBible
from osis import OSISBible
from csvbible import CSVBible
from db import BibleDB
from http import HTTPBible
log = logging.getLogger(__name__)
@ -137,11 +137,13 @@ class BibleManager(object):
log.debug(u'Bible Name: "%s"', name)
self.db_cache[name] = bible
# look to see if lazy load bible exists and get create getter.
source = self.db_cache[name].get_meta(u'download source')
source = self.db_cache[name].get_object(BibleMeta,
u'download source')
if source:
download_name = \
self.db_cache[name].get_meta(u'download name').value
meta_proxy = self.db_cache[name].get_meta(u'proxy url')
download_name = self.db_cache[name].get_object(BibleMeta,
u'download name').value
meta_proxy = self.db_cache[name].get_object(BibleMeta,
u'proxy url')
web_bible = HTTPBible(self.parent, path=self.path,
file=filename, download_source=source.value,
download_name=download_name)
@ -196,7 +198,7 @@ class BibleManager(object):
u'name': book.name,
u'chapters': self.db_cache[bible].get_chapter_count(book.name)
}
for book in self.db_cache[bible].get_books()
for book in self.db_cache[bible].get_all_objects(Book, Book.id)
]
def get_chapter_count(self, bible, book):
@ -249,7 +251,7 @@ class BibleManager(object):
Returns the meta data for a given key
"""
log.debug(u'get_meta %s,%s', bible, key)
return self.db_cache[bible].get_meta(key)
return self.db_cache[bible].get_object(BibleMeta, key)
def exists(self, name):
"""

View File

@ -1,94 +0,0 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=80 tabstop=4 softtabstop=4
###############################################################################
# OpenLP - Open Source Lyrics Projection #
# --------------------------------------------------------------------------- #
# Copyright (c) 2008-2010 Raoul Snyman #
# Portions copyright (c) 2008-2010 Tim Bentley, Jonathan Corwin, Michael #
# Gorven, Scott Guerrieri, Christian Richter, Maikel Stuivenberg, Martin #
# Thompson, Jon Tibble, Carsten Tinggaard #
# --------------------------------------------------------------------------- #
# This program is free software; you can redistribute it and/or modify it #
# under the terms of the GNU General Public License as published by the Free #
# Software Foundation; version 2 of the License. #
# #
# This program is distributed in the hope that it will be useful, but WITHOUT #
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or #
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for #
# more details. #
# #
# You should have received a copy of the GNU General Public License along #
# with this program; if not, write to the Free Software Foundation, Inc., 59 #
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
###############################################################################
from sqlalchemy import Column, Table, MetaData, ForeignKey, types, \
create_engine
from sqlalchemy.orm import mapper, relation, sessionmaker, scoped_session
from openlp.core.lib.db import BaseModel
class BibleMeta(BaseModel):
"""
Bible Meta Data
"""
pass
class Testament(BaseModel):
"""
Bible Testaments
"""
pass
class Book(BaseModel):
"""
Song model
"""
pass
class Verse(BaseModel):
"""
Topic model
"""
pass
def init_models(db_url):
engine = create_engine(db_url)
metadata.bind = engine
session = scoped_session(sessionmaker(autoflush=True, autocommit=False,
bind=engine))
return session
metadata = MetaData()
meta_table = Table(u'metadata', metadata,
Column(u'key', types.Unicode(255), primary_key=True, index=True),
Column(u'value', types.Unicode(255)),
)
testament_table = Table(u'testament', metadata,
Column(u'id', types.Integer, primary_key=True),
Column(u'name', types.Unicode(50)),
)
book_table = Table(u'book', metadata,
Column(u'id', types.Integer, primary_key=True),
Column(u'testament_id', types.Integer, ForeignKey(u'testament.id')),
Column(u'name', types.Unicode(50), index=True),
Column(u'abbreviation', types.Unicode(5), index=True),
)
verse_table = Table(u'verse', metadata,
Column(u'id', types.Integer, primary_key=True, index=True),
Column(u'book_id', types.Integer, ForeignKey(u'book.id'), index=True),
Column(u'chapter', types.Integer, index=True),
Column(u'verse', types.Integer, index=True),
Column(u'text', types.UnicodeText, index=True),
)
mapper(BibleMeta, meta_table)
mapper(Testament, testament_table,
properties={'books': relation(Book, backref='testament')})
mapper(Book, book_table,
properties={'verses': relation(Verse, backref='book')})
mapper(Verse, verse_table)

View File

@ -90,7 +90,7 @@ class OpenSongBible(BibleDB):
QtCore.QString('%s %s %s' % (
translate(u'BiblesPlugin.Opensong', u'Importing'), \
db_book.name, chapter.attrib[u'n'])))
self.commit()
self.session.commit()
except IOError:
log.exception(u'Loading bible from OpenSong file failed')
success = False

View File

@ -136,7 +136,7 @@ class OSISBible(BibleDB):
self.wizard.ImportProgressBar.setMaximum(260)
if last_chapter != chapter:
if last_chapter != 0:
self.commit()
self.session.commit()
self.wizard.incrementProgressBar(
u'Importing %s %s...' % \
(self.books[match.group(1)][0], chapter))
@ -162,7 +162,7 @@ class OSISBible(BibleDB):
verse_text = self.spaces_regex.sub(u' ', verse_text)
self.create_verse(db_book.id, chapter, verse, verse_text)
Receiver.send_message(u'openlp_process_events')
self.commit()
self.session.commit()
self.wizard.incrementProgressBar(u'Finishing import...')
if match_count == 0:
success = False

View File

@ -28,8 +28,8 @@ import string
from PyQt4 import QtGui
from openlp.core.lib import SongXMLBuilder
from openlp.plugins.songs.lib import VerseType
from openlp.plugins.songs.lib.db import Song, Author, Topic, Book
from openlp.plugins.songs.forms import VerseType
class SongImport(object):
"""