mirror of
https://github.com/Mikaela/Limnoria.git
synced 2024-11-27 05:09:23 +01:00
Database independence stuff.
This commit is contained in:
parent
cebf388513
commit
49c465c1c7
@ -82,8 +82,6 @@ def configure(advanced):
|
||||
from supybot.questions import expect, anything, something, yn
|
||||
conf.registerPlugin('Infobot', True)
|
||||
|
||||
filename = conf.supybot.directories.data.dirize('Infobot.db')
|
||||
|
||||
ends = ['!',
|
||||
'.',
|
||||
', $who.',]
|
||||
@ -123,11 +121,12 @@ initialAre = {'who': '<reply>',
|
||||
}
|
||||
|
||||
class PickleInfobotDB(object):
|
||||
def __init__(self):
|
||||
def __init__(self, filename):
|
||||
self._changes = 0
|
||||
self._responses = 0
|
||||
self.filename = filename
|
||||
try:
|
||||
fd = file(filename)
|
||||
fd = file(self.filename)
|
||||
except EnvironmentError:
|
||||
self._is = utils.InsensitivePreservingDict()
|
||||
self._are = utils.InsensitivePreservingDict()
|
||||
@ -143,7 +142,7 @@ class PickleInfobotDB(object):
|
||||
raise dbi.InvalidDBError, str(e)
|
||||
|
||||
def flush(self):
|
||||
fd = utils.transactionalFile(filename, 'wb')
|
||||
fd = utils.transactionalFile(self.filename, 'wb')
|
||||
pickle.dump((self._is, self._are), fd)
|
||||
fd.close()
|
||||
|
||||
@ -228,7 +227,7 @@ class PickleInfobotDB(object):
|
||||
return len(self._are.keys()) + len(self._is.keys())
|
||||
|
||||
class SqliteInfobotDB(object):
|
||||
def __init__(self):
|
||||
def __init__(self, filename):
|
||||
try:
|
||||
import sqlite
|
||||
except ImportError:
|
||||
@ -237,23 +236,13 @@ class SqliteInfobotDB(object):
|
||||
'<http://pysqlite.sf.net/>'
|
||||
self._changes = 0
|
||||
self._responses = 0
|
||||
self.db = None
|
||||
|
||||
def _getDb(self):
|
||||
self.filename = filename
|
||||
try:
|
||||
import sqlite
|
||||
except ImportError:
|
||||
raise callbacks.Error, 'You need to have PySQLite installed to '\
|
||||
'use this plugin. Download it at '\
|
||||
'<http://pysqlite.sf.net/>'
|
||||
if self.db is not None:
|
||||
return self.db
|
||||
try:
|
||||
if os.path.exists(filename):
|
||||
self.db = sqlite.connect(filename)
|
||||
if os.path.exists(self.filename):
|
||||
self.db = sqlite.connect(self.filename)
|
||||
return self.db
|
||||
#else:
|
||||
self.db = sqlite.connect(filename)
|
||||
self.db = sqlite.connect(self.filename)
|
||||
cursor = self.db.cursor()
|
||||
cursor.execute("""CREATE TABLE isFacts (
|
||||
key TEXT UNIQUE ON CONFLICT REPLACE,
|
||||
@ -269,17 +258,14 @@ class SqliteInfobotDB(object):
|
||||
for (k, v) in initialAre.iteritems():
|
||||
self.setAre(k, v)
|
||||
self._changes = 0
|
||||
return self.db
|
||||
except sqlite.DatabaseError, e:
|
||||
raise dbi.InvalidDBError, str(e)
|
||||
|
||||
def close(self):
|
||||
if self.db is not None:
|
||||
self.db.close()
|
||||
self.db.close()
|
||||
|
||||
def changeIs(self, factoid, replacer):
|
||||
db = self._getDb()
|
||||
cursor = db.cursor()
|
||||
cursor = self.db.cursor()
|
||||
cursor.execute("""SELECT value FROM isFacts WHERE key=%s""", factoid)
|
||||
if cursor.rowcount == 0:
|
||||
raise dbi.NoRecordError
|
||||
@ -287,42 +273,37 @@ class SqliteInfobotDB(object):
|
||||
if replacer is not None:
|
||||
cursor.execute("""UPDATE isFacts SET value=%s WHERE key=%s""",
|
||||
replacer(old), factoid)
|
||||
db.commit()
|
||||
self.db.commit()
|
||||
self._changes += 1
|
||||
|
||||
def getIs(self, factoid):
|
||||
db = self._getDb()
|
||||
cursor = db.cursor()
|
||||
cursor = self.db.cursor()
|
||||
cursor.execute("""SELECT value FROM isFacts WHERE key=%s""", factoid)
|
||||
ret = cursor.fetchone()[0]
|
||||
self._responses += 1
|
||||
return ret
|
||||
|
||||
def setIs(self, fact, oid):
|
||||
db = self._getDb()
|
||||
cursor = db.cursor()
|
||||
cursor = self.db.cursor()
|
||||
cursor.execute("""INSERT INTO isFacts VALUES (%s, %s)""", fact, oid)
|
||||
db.commit()
|
||||
self.db.commit()
|
||||
self._changes += 1
|
||||
|
||||
def delIs(self, factoid):
|
||||
db = self._getDb()
|
||||
cursor = db.cursor()
|
||||
cursor = self.db.cursor()
|
||||
cursor.execute("""DELETE FROM isFacts WHERE key=%s""", factoid)
|
||||
if cursor.rowcount == 0:
|
||||
raise dbi.NoRecordError
|
||||
db.commit()
|
||||
self.db.commit()
|
||||
self._changes += 1
|
||||
|
||||
def hasIs(self, factoid):
|
||||
db = self._getDb()
|
||||
cursor = db.cursor()
|
||||
cursor = self.db.cursor()
|
||||
cursor.execute("""SELECT * FROM isFacts WHERE key=%s""", factoid)
|
||||
return cursor.rowcount == 1
|
||||
|
||||
def changeAre(self, factoid, replacer):
|
||||
db = self._getDb()
|
||||
cursor = db.cursor()
|
||||
cursor = self.db.cursor()
|
||||
cursor.execute("""SELECT value FROM areFacts WHERE key=%s""", factoid)
|
||||
if cursor.rowcount == 0:
|
||||
raise dbi.NoRecordError
|
||||
@ -330,36 +311,32 @@ class SqliteInfobotDB(object):
|
||||
if replacer is not None:
|
||||
cursor.execute("""UPDATE areFacts SET value=%s WHERE key=%s""",
|
||||
replacer(old), factoid)
|
||||
db.commit()
|
||||
self.db.commit()
|
||||
self._changes += 1
|
||||
|
||||
def getAre(self, factoid):
|
||||
db = self._getDb()
|
||||
cursor = db.cursor()
|
||||
cursor = self.db.cursor()
|
||||
cursor.execute("""SELECT value FROM areFacts WHERE key=%s""", factoid)
|
||||
ret = cursor.fetchone()[0]
|
||||
self._responses += 1
|
||||
return ret
|
||||
|
||||
def setAre(self, fact, oid):
|
||||
db = self._getDb()
|
||||
cursor = db.cursor()
|
||||
cursor = self.db.cursor()
|
||||
cursor.execute("""INSERT INTO areFacts VALUES (%s, %s)""", fact, oid)
|
||||
db.commit()
|
||||
self.db.commit()
|
||||
self._changes += 1
|
||||
|
||||
def delAre(self, factoid):
|
||||
db = self._getDb()
|
||||
cursor = db.cursor()
|
||||
cursor = self.db.cursor()
|
||||
cursor.execute("""DELETE FROM areFacts WHERE key=%s""", factoid)
|
||||
if cursor.rowcount == 0:
|
||||
raise dbi.NoRecordError
|
||||
db.commit()
|
||||
self.db.commit()
|
||||
self._changes += 1
|
||||
|
||||
def hasAre(self, factoid):
|
||||
db = self._getDb()
|
||||
cursor = db.cursor()
|
||||
cursor = self.db.cursor()
|
||||
cursor.execute("""SELECT * FROM areFacts WHERE key=%s""", factoid)
|
||||
return cursor.rowcount == 1
|
||||
|
||||
@ -376,16 +353,17 @@ class SqliteInfobotDB(object):
|
||||
return self._responses
|
||||
|
||||
def getNumFacts(self):
|
||||
db = self._getDb()
|
||||
cursor = db.cursor()
|
||||
cursor = self.db.cursor()
|
||||
cursor.execute("""SELECT COUNT(*) FROM areFacts""")
|
||||
areFacts = int(cursor.fetchone()[0])
|
||||
cursor.execute("""SELECT COUNT(*) FROM isFacts""")
|
||||
isFacts = int(cursor.fetchone()[0])
|
||||
return areFacts + isFacts
|
||||
|
||||
def InfobotDB():
|
||||
return SqliteInfobotDB()
|
||||
|
||||
InfobotDB = plugins.DB('Infobot',
|
||||
{'sqlite': SqliteInfobotDB,
|
||||
'pickle': PickleInfobotDB})
|
||||
|
||||
class Dunno(Exception):
|
||||
pass
|
||||
@ -397,7 +375,7 @@ class Infobot(callbacks.PrivmsgCommandAndRegexp):
|
||||
try:
|
||||
self.db = InfobotDB()
|
||||
except Exception:
|
||||
self.log.exception('Error loading %s:', filename)
|
||||
self.log.exception('Error loading %s:', self.filename)
|
||||
raise # So it doesn't get loaded without its database.
|
||||
self.irc = None
|
||||
self.msg = None
|
||||
|
@ -155,9 +155,10 @@ class DbiNoteDB(dbi.DB):
|
||||
return id
|
||||
|
||||
|
||||
def NoteDB():
|
||||
# XXX This should eventually be smarter.
|
||||
return DbiNoteDB(conf.supybot.directories.data.dirize('Note.db'))
|
||||
NoteDB = plugins.DB('Note', {'flat': DbiNoteDB})
|
||||
## def NoteDB():
|
||||
## # XXX This should eventually be smarter.
|
||||
## return DbiNoteDB(conf.supybot.directories.data.dirize('Note.db'))
|
||||
|
||||
|
||||
class Note(callbacks.Privmsg):
|
||||
|
@ -55,14 +55,22 @@ import supybot.ircutils as ircutils
|
||||
import supybot.webutils as webutils
|
||||
|
||||
try:
|
||||
# We need to sweep away all that mx.* crap because our code doesn't account
|
||||
# for PySQLite's arbitrary use of it. Whoever decided to change sqlite's
|
||||
# behavior based on whether or not that module is installed was a *CRACK*
|
||||
# **FIEND**, plain and simple.
|
||||
mxCrap = {}
|
||||
for (name, module) in sys.modules.items():
|
||||
if name.startswith('mx'):
|
||||
mxCrap[name] = module
|
||||
sys.modules[name] = None
|
||||
# Now that the mx crap is gone, we can import sqlite.
|
||||
import sqlite
|
||||
# And now we'll put it back, even though it sucks.
|
||||
for (name, module) in mxCrap.items():
|
||||
sys.modules[name] = module
|
||||
# Just in case, we'll do this as well. It doesn't seem to work fine by
|
||||
# itself, though, or else we'd just do this in the first place.
|
||||
sqlite.have_datetime = False
|
||||
Connection = sqlite.Connection
|
||||
class MyConnection(sqlite.Connection):
|
||||
@ -75,6 +83,30 @@ try:
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
|
||||
class NoSuitableDatabase(Exception):
|
||||
def __init__(self, suitable):
|
||||
self.suitable = suitable
|
||||
self.suitable.sort()
|
||||
|
||||
def __str__(self):
|
||||
return 'No suitable databases were found. Suitable databases ' \
|
||||
'include %s.' % utils.commaAndify(self.suitable)
|
||||
|
||||
def DB(filename, types):
|
||||
filename = conf.supybot.directories.data.dirize(filename)
|
||||
def MakeDB(*args, **kwargs):
|
||||
for type in conf.supybot.databases():
|
||||
# Can't do this because Python sucks. Go ahead, try it!
|
||||
# filename = '.'.join([filename, type, 'db'])
|
||||
fn = '.'.join([filename, type, 'db'])
|
||||
try:
|
||||
return types[type](fn, *args, **kwargs)
|
||||
except KeyError:
|
||||
continue
|
||||
raise NoSuitableDatabase, types.keys()
|
||||
return MakeDB
|
||||
|
||||
class DBHandler(object):
|
||||
def __init__(self, name=None, suffix='.db'):
|
||||
if name is None:
|
||||
|
18
src/conf.py
18
src/conf.py
@ -627,6 +627,7 @@ registerGlobalValue(supybot.directories.data, 'tmp',
|
||||
# Remember, we're *meant* to replace this nice little wrapper.
|
||||
def transactionalFile(*args, **kwargs):
|
||||
kwargs['tmpDir'] = supybot.directories.data.tmp()
|
||||
# ??? Should we offer an option not to makeBackupIfSmaller?
|
||||
return utils.AtomicFile(*args, **kwargs)
|
||||
utils.transactionalFile = transactionalFile
|
||||
|
||||
@ -658,7 +659,20 @@ registerGlobalValue(supybot.plugins, 'alwaysLoadDefault',
|
||||
###
|
||||
# supybot.databases. For stuff relating to Supybot's databases (duh!)
|
||||
###
|
||||
registerGroup(supybot, 'databases')
|
||||
class Databases(registry.SpaceSeparatedListOfStrings):
|
||||
def __call__(self):
|
||||
v = super(Databases, self).__call__()
|
||||
if not v:
|
||||
v = ['flat', 'cdb', 'pickle']
|
||||
if 'sqlite' in sys.modules:
|
||||
v.insert(0, 'sqlite')
|
||||
return v
|
||||
|
||||
registerGlobalValue(supybot, 'databases',
|
||||
Databases([], """Determines what databases are available for use. If this
|
||||
value is not configured (that is, if its value is empty) then sane defaults
|
||||
will be provided."""))
|
||||
|
||||
registerGroup(supybot.databases, 'users')
|
||||
registerGlobalValue(supybot.databases.users, 'filename',
|
||||
registry.String('users.conf', """Determines what filename will be used for
|
||||
@ -691,6 +705,8 @@ registerChannelValue(supybot.databases.plugins, 'channelSpecific',
|
||||
can be channel-specific will be so. This can be overridden by individual
|
||||
channels."""))
|
||||
|
||||
# XXX Configuration variables for dbi, sqlite, flat, mysql, etc.
|
||||
|
||||
###
|
||||
# Protocol information.
|
||||
###
|
||||
|
Loading…
Reference in New Issue
Block a user