mirror of
https://github.com/Mikaela/Limnoria.git
synced 2024-11-27 13:19:24 +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
|
from supybot.questions import expect, anything, something, yn
|
||||||
conf.registerPlugin('Infobot', True)
|
conf.registerPlugin('Infobot', True)
|
||||||
|
|
||||||
filename = conf.supybot.directories.data.dirize('Infobot.db')
|
|
||||||
|
|
||||||
ends = ['!',
|
ends = ['!',
|
||||||
'.',
|
'.',
|
||||||
', $who.',]
|
', $who.',]
|
||||||
@ -123,11 +121,12 @@ initialAre = {'who': '<reply>',
|
|||||||
}
|
}
|
||||||
|
|
||||||
class PickleInfobotDB(object):
|
class PickleInfobotDB(object):
|
||||||
def __init__(self):
|
def __init__(self, filename):
|
||||||
self._changes = 0
|
self._changes = 0
|
||||||
self._responses = 0
|
self._responses = 0
|
||||||
|
self.filename = filename
|
||||||
try:
|
try:
|
||||||
fd = file(filename)
|
fd = file(self.filename)
|
||||||
except EnvironmentError:
|
except EnvironmentError:
|
||||||
self._is = utils.InsensitivePreservingDict()
|
self._is = utils.InsensitivePreservingDict()
|
||||||
self._are = utils.InsensitivePreservingDict()
|
self._are = utils.InsensitivePreservingDict()
|
||||||
@ -143,7 +142,7 @@ class PickleInfobotDB(object):
|
|||||||
raise dbi.InvalidDBError, str(e)
|
raise dbi.InvalidDBError, str(e)
|
||||||
|
|
||||||
def flush(self):
|
def flush(self):
|
||||||
fd = utils.transactionalFile(filename, 'wb')
|
fd = utils.transactionalFile(self.filename, 'wb')
|
||||||
pickle.dump((self._is, self._are), fd)
|
pickle.dump((self._is, self._are), fd)
|
||||||
fd.close()
|
fd.close()
|
||||||
|
|
||||||
@ -228,7 +227,7 @@ class PickleInfobotDB(object):
|
|||||||
return len(self._are.keys()) + len(self._is.keys())
|
return len(self._are.keys()) + len(self._is.keys())
|
||||||
|
|
||||||
class SqliteInfobotDB(object):
|
class SqliteInfobotDB(object):
|
||||||
def __init__(self):
|
def __init__(self, filename):
|
||||||
try:
|
try:
|
||||||
import sqlite
|
import sqlite
|
||||||
except ImportError:
|
except ImportError:
|
||||||
@ -237,23 +236,13 @@ class SqliteInfobotDB(object):
|
|||||||
'<http://pysqlite.sf.net/>'
|
'<http://pysqlite.sf.net/>'
|
||||||
self._changes = 0
|
self._changes = 0
|
||||||
self._responses = 0
|
self._responses = 0
|
||||||
self.db = None
|
self.filename = filename
|
||||||
|
|
||||||
def _getDb(self):
|
|
||||||
try:
|
try:
|
||||||
import sqlite
|
if os.path.exists(self.filename):
|
||||||
except ImportError:
|
self.db = sqlite.connect(self.filename)
|
||||||
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)
|
|
||||||
return self.db
|
return self.db
|
||||||
#else:
|
#else:
|
||||||
self.db = sqlite.connect(filename)
|
self.db = sqlite.connect(self.filename)
|
||||||
cursor = self.db.cursor()
|
cursor = self.db.cursor()
|
||||||
cursor.execute("""CREATE TABLE isFacts (
|
cursor.execute("""CREATE TABLE isFacts (
|
||||||
key TEXT UNIQUE ON CONFLICT REPLACE,
|
key TEXT UNIQUE ON CONFLICT REPLACE,
|
||||||
@ -269,17 +258,14 @@ class SqliteInfobotDB(object):
|
|||||||
for (k, v) in initialAre.iteritems():
|
for (k, v) in initialAre.iteritems():
|
||||||
self.setAre(k, v)
|
self.setAre(k, v)
|
||||||
self._changes = 0
|
self._changes = 0
|
||||||
return self.db
|
|
||||||
except sqlite.DatabaseError, e:
|
except sqlite.DatabaseError, e:
|
||||||
raise dbi.InvalidDBError, str(e)
|
raise dbi.InvalidDBError, str(e)
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
if self.db is not None:
|
|
||||||
self.db.close()
|
self.db.close()
|
||||||
|
|
||||||
def changeIs(self, factoid, replacer):
|
def changeIs(self, factoid, replacer):
|
||||||
db = self._getDb()
|
cursor = self.db.cursor()
|
||||||
cursor = db.cursor()
|
|
||||||
cursor.execute("""SELECT value FROM isFacts WHERE key=%s""", factoid)
|
cursor.execute("""SELECT value FROM isFacts WHERE key=%s""", factoid)
|
||||||
if cursor.rowcount == 0:
|
if cursor.rowcount == 0:
|
||||||
raise dbi.NoRecordError
|
raise dbi.NoRecordError
|
||||||
@ -287,42 +273,37 @@ class SqliteInfobotDB(object):
|
|||||||
if replacer is not None:
|
if replacer is not None:
|
||||||
cursor.execute("""UPDATE isFacts SET value=%s WHERE key=%s""",
|
cursor.execute("""UPDATE isFacts SET value=%s WHERE key=%s""",
|
||||||
replacer(old), factoid)
|
replacer(old), factoid)
|
||||||
db.commit()
|
self.db.commit()
|
||||||
self._changes += 1
|
self._changes += 1
|
||||||
|
|
||||||
def getIs(self, factoid):
|
def getIs(self, factoid):
|
||||||
db = self._getDb()
|
cursor = self.db.cursor()
|
||||||
cursor = db.cursor()
|
|
||||||
cursor.execute("""SELECT value FROM isFacts WHERE key=%s""", factoid)
|
cursor.execute("""SELECT value FROM isFacts WHERE key=%s""", factoid)
|
||||||
ret = cursor.fetchone()[0]
|
ret = cursor.fetchone()[0]
|
||||||
self._responses += 1
|
self._responses += 1
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def setIs(self, fact, oid):
|
def setIs(self, fact, oid):
|
||||||
db = self._getDb()
|
cursor = self.db.cursor()
|
||||||
cursor = db.cursor()
|
|
||||||
cursor.execute("""INSERT INTO isFacts VALUES (%s, %s)""", fact, oid)
|
cursor.execute("""INSERT INTO isFacts VALUES (%s, %s)""", fact, oid)
|
||||||
db.commit()
|
self.db.commit()
|
||||||
self._changes += 1
|
self._changes += 1
|
||||||
|
|
||||||
def delIs(self, factoid):
|
def delIs(self, factoid):
|
||||||
db = self._getDb()
|
cursor = self.db.cursor()
|
||||||
cursor = db.cursor()
|
|
||||||
cursor.execute("""DELETE FROM isFacts WHERE key=%s""", factoid)
|
cursor.execute("""DELETE FROM isFacts WHERE key=%s""", factoid)
|
||||||
if cursor.rowcount == 0:
|
if cursor.rowcount == 0:
|
||||||
raise dbi.NoRecordError
|
raise dbi.NoRecordError
|
||||||
db.commit()
|
self.db.commit()
|
||||||
self._changes += 1
|
self._changes += 1
|
||||||
|
|
||||||
def hasIs(self, factoid):
|
def hasIs(self, factoid):
|
||||||
db = self._getDb()
|
cursor = self.db.cursor()
|
||||||
cursor = db.cursor()
|
|
||||||
cursor.execute("""SELECT * FROM isFacts WHERE key=%s""", factoid)
|
cursor.execute("""SELECT * FROM isFacts WHERE key=%s""", factoid)
|
||||||
return cursor.rowcount == 1
|
return cursor.rowcount == 1
|
||||||
|
|
||||||
def changeAre(self, factoid, replacer):
|
def changeAre(self, factoid, replacer):
|
||||||
db = self._getDb()
|
cursor = self.db.cursor()
|
||||||
cursor = db.cursor()
|
|
||||||
cursor.execute("""SELECT value FROM areFacts WHERE key=%s""", factoid)
|
cursor.execute("""SELECT value FROM areFacts WHERE key=%s""", factoid)
|
||||||
if cursor.rowcount == 0:
|
if cursor.rowcount == 0:
|
||||||
raise dbi.NoRecordError
|
raise dbi.NoRecordError
|
||||||
@ -330,36 +311,32 @@ class SqliteInfobotDB(object):
|
|||||||
if replacer is not None:
|
if replacer is not None:
|
||||||
cursor.execute("""UPDATE areFacts SET value=%s WHERE key=%s""",
|
cursor.execute("""UPDATE areFacts SET value=%s WHERE key=%s""",
|
||||||
replacer(old), factoid)
|
replacer(old), factoid)
|
||||||
db.commit()
|
self.db.commit()
|
||||||
self._changes += 1
|
self._changes += 1
|
||||||
|
|
||||||
def getAre(self, factoid):
|
def getAre(self, factoid):
|
||||||
db = self._getDb()
|
cursor = self.db.cursor()
|
||||||
cursor = db.cursor()
|
|
||||||
cursor.execute("""SELECT value FROM areFacts WHERE key=%s""", factoid)
|
cursor.execute("""SELECT value FROM areFacts WHERE key=%s""", factoid)
|
||||||
ret = cursor.fetchone()[0]
|
ret = cursor.fetchone()[0]
|
||||||
self._responses += 1
|
self._responses += 1
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def setAre(self, fact, oid):
|
def setAre(self, fact, oid):
|
||||||
db = self._getDb()
|
cursor = self.db.cursor()
|
||||||
cursor = db.cursor()
|
|
||||||
cursor.execute("""INSERT INTO areFacts VALUES (%s, %s)""", fact, oid)
|
cursor.execute("""INSERT INTO areFacts VALUES (%s, %s)""", fact, oid)
|
||||||
db.commit()
|
self.db.commit()
|
||||||
self._changes += 1
|
self._changes += 1
|
||||||
|
|
||||||
def delAre(self, factoid):
|
def delAre(self, factoid):
|
||||||
db = self._getDb()
|
cursor = self.db.cursor()
|
||||||
cursor = db.cursor()
|
|
||||||
cursor.execute("""DELETE FROM areFacts WHERE key=%s""", factoid)
|
cursor.execute("""DELETE FROM areFacts WHERE key=%s""", factoid)
|
||||||
if cursor.rowcount == 0:
|
if cursor.rowcount == 0:
|
||||||
raise dbi.NoRecordError
|
raise dbi.NoRecordError
|
||||||
db.commit()
|
self.db.commit()
|
||||||
self._changes += 1
|
self._changes += 1
|
||||||
|
|
||||||
def hasAre(self, factoid):
|
def hasAre(self, factoid):
|
||||||
db = self._getDb()
|
cursor = self.db.cursor()
|
||||||
cursor = db.cursor()
|
|
||||||
cursor.execute("""SELECT * FROM areFacts WHERE key=%s""", factoid)
|
cursor.execute("""SELECT * FROM areFacts WHERE key=%s""", factoid)
|
||||||
return cursor.rowcount == 1
|
return cursor.rowcount == 1
|
||||||
|
|
||||||
@ -376,16 +353,17 @@ class SqliteInfobotDB(object):
|
|||||||
return self._responses
|
return self._responses
|
||||||
|
|
||||||
def getNumFacts(self):
|
def getNumFacts(self):
|
||||||
db = self._getDb()
|
cursor = self.db.cursor()
|
||||||
cursor = db.cursor()
|
|
||||||
cursor.execute("""SELECT COUNT(*) FROM areFacts""")
|
cursor.execute("""SELECT COUNT(*) FROM areFacts""")
|
||||||
areFacts = int(cursor.fetchone()[0])
|
areFacts = int(cursor.fetchone()[0])
|
||||||
cursor.execute("""SELECT COUNT(*) FROM isFacts""")
|
cursor.execute("""SELECT COUNT(*) FROM isFacts""")
|
||||||
isFacts = int(cursor.fetchone()[0])
|
isFacts = int(cursor.fetchone()[0])
|
||||||
return areFacts + isFacts
|
return areFacts + isFacts
|
||||||
|
|
||||||
def InfobotDB():
|
|
||||||
return SqliteInfobotDB()
|
InfobotDB = plugins.DB('Infobot',
|
||||||
|
{'sqlite': SqliteInfobotDB,
|
||||||
|
'pickle': PickleInfobotDB})
|
||||||
|
|
||||||
class Dunno(Exception):
|
class Dunno(Exception):
|
||||||
pass
|
pass
|
||||||
@ -397,7 +375,7 @@ class Infobot(callbacks.PrivmsgCommandAndRegexp):
|
|||||||
try:
|
try:
|
||||||
self.db = InfobotDB()
|
self.db = InfobotDB()
|
||||||
except Exception:
|
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.
|
raise # So it doesn't get loaded without its database.
|
||||||
self.irc = None
|
self.irc = None
|
||||||
self.msg = None
|
self.msg = None
|
||||||
|
@ -155,9 +155,10 @@ class DbiNoteDB(dbi.DB):
|
|||||||
return id
|
return id
|
||||||
|
|
||||||
|
|
||||||
def NoteDB():
|
NoteDB = plugins.DB('Note', {'flat': DbiNoteDB})
|
||||||
# XXX This should eventually be smarter.
|
## def NoteDB():
|
||||||
return DbiNoteDB(conf.supybot.directories.data.dirize('Note.db'))
|
## # XXX This should eventually be smarter.
|
||||||
|
## return DbiNoteDB(conf.supybot.directories.data.dirize('Note.db'))
|
||||||
|
|
||||||
|
|
||||||
class Note(callbacks.Privmsg):
|
class Note(callbacks.Privmsg):
|
||||||
|
@ -55,14 +55,22 @@ import supybot.ircutils as ircutils
|
|||||||
import supybot.webutils as webutils
|
import supybot.webutils as webutils
|
||||||
|
|
||||||
try:
|
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 = {}
|
mxCrap = {}
|
||||||
for (name, module) in sys.modules.items():
|
for (name, module) in sys.modules.items():
|
||||||
if name.startswith('mx'):
|
if name.startswith('mx'):
|
||||||
mxCrap[name] = module
|
mxCrap[name] = module
|
||||||
sys.modules[name] = None
|
sys.modules[name] = None
|
||||||
|
# Now that the mx crap is gone, we can import sqlite.
|
||||||
import sqlite
|
import sqlite
|
||||||
|
# And now we'll put it back, even though it sucks.
|
||||||
for (name, module) in mxCrap.items():
|
for (name, module) in mxCrap.items():
|
||||||
sys.modules[name] = module
|
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
|
sqlite.have_datetime = False
|
||||||
Connection = sqlite.Connection
|
Connection = sqlite.Connection
|
||||||
class MyConnection(sqlite.Connection):
|
class MyConnection(sqlite.Connection):
|
||||||
@ -75,6 +83,30 @@ try:
|
|||||||
except ImportError:
|
except ImportError:
|
||||||
pass
|
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):
|
class DBHandler(object):
|
||||||
def __init__(self, name=None, suffix='.db'):
|
def __init__(self, name=None, suffix='.db'):
|
||||||
if name is None:
|
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.
|
# Remember, we're *meant* to replace this nice little wrapper.
|
||||||
def transactionalFile(*args, **kwargs):
|
def transactionalFile(*args, **kwargs):
|
||||||
kwargs['tmpDir'] = supybot.directories.data.tmp()
|
kwargs['tmpDir'] = supybot.directories.data.tmp()
|
||||||
|
# ??? Should we offer an option not to makeBackupIfSmaller?
|
||||||
return utils.AtomicFile(*args, **kwargs)
|
return utils.AtomicFile(*args, **kwargs)
|
||||||
utils.transactionalFile = transactionalFile
|
utils.transactionalFile = transactionalFile
|
||||||
|
|
||||||
@ -658,7 +659,20 @@ registerGlobalValue(supybot.plugins, 'alwaysLoadDefault',
|
|||||||
###
|
###
|
||||||
# supybot.databases. For stuff relating to Supybot's databases (duh!)
|
# 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')
|
registerGroup(supybot.databases, 'users')
|
||||||
registerGlobalValue(supybot.databases.users, 'filename',
|
registerGlobalValue(supybot.databases.users, 'filename',
|
||||||
registry.String('users.conf', """Determines what filename will be used for
|
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
|
can be channel-specific will be so. This can be overridden by individual
|
||||||
channels."""))
|
channels."""))
|
||||||
|
|
||||||
|
# XXX Configuration variables for dbi, sqlite, flat, mysql, etc.
|
||||||
|
|
||||||
###
|
###
|
||||||
# Protocol information.
|
# Protocol information.
|
||||||
###
|
###
|
||||||
|
Loading…
Reference in New Issue
Block a user