1. Enhance cursor.py to support updating records after reading them
2. Implement enhancement in write.py, get_cursor method 3. Exploit new capability in ChangeNames.py svn: r13237
This commit is contained in:
parent
dd10d9bfdb
commit
9b586eaf4f
@ -23,7 +23,8 @@
|
||||
# Standard python modules
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
import cPickle as pickle
|
||||
from cPickle import dumps, loads
|
||||
from bsddb import db
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
@ -44,12 +45,15 @@ class GrampsCursor(object):
|
||||
should be used.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self, txn=None, update=False, commit=False):
|
||||
"""
|
||||
Instantiate the object. Note, this method should be overridden in
|
||||
derived classes that properly set self.cursor and self.source
|
||||
"""
|
||||
self.cursor = self.source = None
|
||||
self.txn = txn
|
||||
self._update = update
|
||||
self.commit = commit
|
||||
|
||||
def __getattr__(self, name):
|
||||
"""
|
||||
@ -68,6 +72,8 @@ class GrampsCursor(object):
|
||||
Context manager exit method
|
||||
"""
|
||||
self.close()
|
||||
if self.txn and self.commit:
|
||||
self.txn.commit()
|
||||
return exc_type is None
|
||||
|
||||
def __iter__(self):
|
||||
@ -76,74 +82,38 @@ class GrampsCursor(object):
|
||||
"""
|
||||
|
||||
data = self.first()
|
||||
_n = self.next # Saved attribute lookup in the loop
|
||||
while data:
|
||||
yield data
|
||||
data = self.next()
|
||||
data = _n()
|
||||
|
||||
def first(self, *args, **kwargs):
|
||||
"""
|
||||
Return the first (index, data) pair in the database.
|
||||
|
||||
This should be called before the first call to next(). Note that the
|
||||
data return is in the format of the serialized format stored in the
|
||||
database, not in the more usable class object. The data should be
|
||||
converted to a class using the class's unserialize method.
|
||||
def _get(_flags=0):
|
||||
""" Closure that returns a cursor get function """
|
||||
|
||||
If no data is available, None is returned.
|
||||
"""
|
||||
|
||||
data = self.cursor.first(*args, **kwargs)
|
||||
if data:
|
||||
return (data[0], pickle.loads(data[1]))
|
||||
return None
|
||||
def get(self, flags=0, **kwargs):
|
||||
"""
|
||||
Issue DBCursor get call (with DB_RMW flag if update requested)
|
||||
Return results to caller
|
||||
"""
|
||||
data = self.cursor.get(
|
||||
_flags | flags | (db.DB_RMW if self._update else 0),
|
||||
**kwargs)
|
||||
|
||||
def next(self, *args, **kwargs):
|
||||
"""
|
||||
Return the next (index, data) pair in the database.
|
||||
|
||||
Like the first() method, the data return is in the format of the
|
||||
serialized format stored in the database, not in the more usable class
|
||||
object. The data should be converted to a class using the class's
|
||||
unserialize method.
|
||||
return (data[0], loads(data[1])) if data else None
|
||||
|
||||
None is returned when no more data is available.
|
||||
"""
|
||||
|
||||
data = self.cursor.next(*args, **kwargs)
|
||||
if data:
|
||||
return (data[0], pickle.loads(data[1]))
|
||||
return None
|
||||
return get
|
||||
|
||||
def prev(self, *args, **kwargs):
|
||||
"""
|
||||
Return the previous (index, data) pair in the database.
|
||||
|
||||
Like the first() method, the data return is in the format of the
|
||||
serialized format stored in the database, not in the more usable class
|
||||
object. The data should be converted to a class using the class's
|
||||
unserialize method.
|
||||
# Use closure to define access methods
|
||||
|
||||
If no data is available, None is returned.
|
||||
"""
|
||||
|
||||
data = self.cursor.prev(*args, **kwargs)
|
||||
if data:
|
||||
return (data[0], pickle.loads(data[1]))
|
||||
return None
|
||||
current = _get(db.DB_CURRENT)
|
||||
first = _get(db.DB_FIRST)
|
||||
next = _get(db.DB_NEXT)
|
||||
last = _get(db.DB_LAST)
|
||||
prev = _get(db.DB_PREV)
|
||||
|
||||
def last(self, *args, **kwargs):
|
||||
def update(self, key, data, flags=0, **kwargs):
|
||||
"""
|
||||
Return the last (index, data) pair in the database.
|
||||
|
||||
Like the first() method, the data return is in the format of the
|
||||
serialized format stored in the database, not in the more usable class
|
||||
object. The data should be converted to a class using the class's
|
||||
unserialize method.
|
||||
|
||||
None is returned when no more data is available.
|
||||
Write the current key, data pair to the database.
|
||||
"""
|
||||
|
||||
data = self.cursor.last(*args, **kwargs)
|
||||
if data:
|
||||
return (data[0], pickle.loads(data[1]))
|
||||
return None
|
||||
self.cursor.put(key, dumps(data), flags=flags | db.DB_CURRENT,
|
||||
**kwargs)
|
||||
|
@ -99,7 +99,8 @@ class GrampsDbBookmarks(object):
|
||||
#-------------------------------------------------------------------------
|
||||
class GrampsDbReadCursor(GrampsCursor):
|
||||
|
||||
def __init__(self, source, txn=None):
|
||||
def __init__(self, source, txn=None, **kwargs):
|
||||
GrampsCursor.__init__(self, txn=txn, **kwargs)
|
||||
self.cursor = source.db.cursor(txn)
|
||||
self.source = source
|
||||
|
||||
@ -280,36 +281,36 @@ class GrampsDbRead(GrampsDbBase, Callback):
|
||||
"""Return True when the file has a supported version."""
|
||||
return True
|
||||
|
||||
def __get_cursor(self, table):
|
||||
def get_cursor(self, table, *args, **kwargs):
|
||||
try:
|
||||
return GrampsDbReadCursor(table, self.txn)
|
||||
except DBERRS, msg:
|
||||
self.__log_error()
|
||||
raise Errors.DbError(msg)
|
||||
|
||||
def get_person_cursor(self):
|
||||
return self.__get_cursor(self.person_map)
|
||||
def get_person_cursor(self, *args, **kwargs):
|
||||
return self.get_cursor(self.person_map, *args, **kwargs)
|
||||
|
||||
def get_family_cursor(self):
|
||||
return self.__get_cursor(self.family_map)
|
||||
def get_family_cursor(self, *args, **kwargs):
|
||||
return self.get_cursor(self.family_map, *args, **kwargs)
|
||||
|
||||
def get_event_cursor(self):
|
||||
return self.__get_cursor(self.event_map)
|
||||
def get_event_cursor(self, *args, **kwargs):
|
||||
return self.get_cursor(self.event_map, *args, **kwargs)
|
||||
|
||||
def get_place_cursor(self):
|
||||
return self.__get_cursor(self.place_map)
|
||||
def get_place_cursor(self, *args, **kwargs):
|
||||
return self.get_cursor(self.place_map, *args, **kwargs)
|
||||
|
||||
def get_source_cursor(self):
|
||||
return self.__get_cursor(self.source_map)
|
||||
def get_source_cursor(self, *args, **kwargs):
|
||||
return self.get_cursor(self.source_map, *args, **kwargs)
|
||||
|
||||
def get_media_cursor(self):
|
||||
return self.__get_cursor(self.media_map)
|
||||
def get_media_cursor(self, *args, **kwargs):
|
||||
return self.get_cursor(self.media_map, *args, **kwargs)
|
||||
|
||||
def get_repository_cursor(self):
|
||||
return self.__get_cursor(self.repository_map)
|
||||
def get_repository_cursor(self, *args, **kwargs):
|
||||
return self.get_cursor(self.repository_map, *args, **kwargs)
|
||||
|
||||
def get_note_cursor(self):
|
||||
return self.__get_cursor(self.note_map)
|
||||
def get_note_cursor(self, *args, **kwargs):
|
||||
return self.get_cursor(self.note_map, *args, **kwargs)
|
||||
|
||||
def load(self, name, callback, mode=DBMODE_R):
|
||||
"""
|
||||
|
@ -142,12 +142,13 @@ def find_referenced_handle(key, data):
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# GrampsDBDirCursor
|
||||
# GrampsWriteCursor
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
class GrampsDBDirCursor(GrampsCursor):
|
||||
class GrampsWriteCursor(GrampsCursor):
|
||||
|
||||
def __init__(self, source, txn=None):
|
||||
def __init__(self, source, txn=None, **kwargs):
|
||||
GrampsCursor.__init__(self, txn=txn, **kwargs)
|
||||
self.cursor = source.db.cursor(txn)
|
||||
self.source = source
|
||||
|
||||
@ -158,7 +159,8 @@ class GrampsDBDirCursor(GrampsCursor):
|
||||
#-------------------------------------------------------------------------
|
||||
class GrampsDBDirAssocCursor(GrampsCursor):
|
||||
|
||||
def __init__(self, source, txn=None):
|
||||
def __init__(self, source, txn=None, **kwargs):
|
||||
GrampsCursor.__init__(self, txn=txn, **kwargs)
|
||||
self.cursor = source.cursor(txn)
|
||||
self.source = source
|
||||
|
||||
@ -257,6 +259,17 @@ class GrampsDBDir(GrampsDbRead, Callback, UpdateCallback):
|
||||
|
||||
_log_error = __log_error
|
||||
|
||||
# Override get_cursor method from the superclass to add udpate
|
||||
# capability
|
||||
|
||||
@catch_db_error
|
||||
def get_cursor(self, table, txn=None, update=False, commit=False):
|
||||
""" Helper function to return a cursor over a table """
|
||||
if update and not txn:
|
||||
txn = self.env.txn_begin(self.txn)
|
||||
return GrampsWriteCursor(table, txn=txn or self.txn,
|
||||
update=update, commit=commit)
|
||||
|
||||
# cursors for lookups in the reference_map for back reference
|
||||
# lookups. The reference_map has three indexes:
|
||||
# the main index: a tuple of (primary_handle, referenced_handle)
|
||||
@ -1802,11 +1815,9 @@ if __name__ == "__main__":
|
||||
d.load(db_path, lambda x: x)
|
||||
|
||||
print d.get_default_person()
|
||||
|
||||
with d.get_person_cursor() as c:
|
||||
for key, data in c:
|
||||
person = Person(data)
|
||||
print key, person.get_primary_name().get_name(),
|
||||
|
||||
print d.surnames.keys()
|
||||
print d.remove_from_surname_list.__doc__
|
||||
|
@ -30,6 +30,8 @@
|
||||
#-------------------------------------------------------------------------
|
||||
import gobject
|
||||
import gtk
|
||||
import cPickle
|
||||
from bsddb.db import DB_CURRENT
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
@ -40,6 +42,7 @@ import const
|
||||
from gui.utils import ProgressMeter
|
||||
import GrampsDisplay
|
||||
import ManagedWindow
|
||||
from gen.lib import Person
|
||||
|
||||
from QuestionDialog import OkDialog
|
||||
from PluginUtils import Tool
|
||||
@ -234,10 +237,10 @@ class ChangeNames(Tool.BatchTool, ManagedWindow.ManagedWindow):
|
||||
for node in self.iter_list
|
||||
if self.model.get_value(node,0)]
|
||||
|
||||
#for handle in self.db.get_person_handles(sort_handles=False):
|
||||
for handle in self.db.get_person_handles(False):
|
||||
with self.db.get_person_cursor(update=True, commit=True) as cursor:
|
||||
for handle, data in cursor:
|
||||
person = Person(data)
|
||||
change = False
|
||||
person = self.db.get_person_from_handle(handle)
|
||||
for name in [person.get_primary_name()] + person.get_alternate_names():
|
||||
sname = name.get_surname()
|
||||
if sname in changelist:
|
||||
@ -245,7 +248,7 @@ class ChangeNames(Tool.BatchTool, ManagedWindow.ManagedWindow):
|
||||
sname = self.name_cap(sname)
|
||||
name.set_surname(sname)
|
||||
if change:
|
||||
self.db.commit_person(person,self.trans)
|
||||
cursor.update(handle, person.serialize())
|
||||
|
||||
self.db.transaction_commit(self.trans,_("Capitalization changes"))
|
||||
self.db.enable_signals()
|
||||
|
Loading…
Reference in New Issue
Block a user