bug 9416 merge conflict
This commit is contained in:
commit
b2e0f437f4
@ -139,6 +139,8 @@ class DbGenericUndo(DbUndo):
|
||||
subitems = transaction.get_recnos()
|
||||
|
||||
# Process all records in the transaction
|
||||
try:
|
||||
self.db.transaction_backend_begin()
|
||||
for record_id in subitems:
|
||||
(key, trans_type, handle, old_data, new_data) = \
|
||||
pickle.loads(self.undodb[record_id])
|
||||
@ -148,6 +150,11 @@ class DbGenericUndo(DbUndo):
|
||||
else:
|
||||
self.undo_data(new_data, handle, self.mapbase[key],
|
||||
db.emit, SIGBASE[key])
|
||||
self.db.transaction_backend_commit()
|
||||
except:
|
||||
self.db.transaction_backend_abort()
|
||||
raise
|
||||
|
||||
# Notify listeners
|
||||
if db.undo_callback:
|
||||
db.undo_callback(_("_Undo %s")
|
||||
@ -847,6 +854,27 @@ class DbGeneric(DbWriteBase, DbReadBase, UpdateCallback, Callback):
|
||||
return self.get_table_func(table_name)
|
||||
return None
|
||||
|
||||
def transaction_backend_begin(self):
|
||||
"""
|
||||
Lowlevel interface to the backend transaction.
|
||||
Executes a db BEGIN;
|
||||
"""
|
||||
pass
|
||||
|
||||
def transaction_backend_commit(self):
|
||||
"""
|
||||
Lowlevel interface to the backend transaction.
|
||||
Executes a db END;
|
||||
"""
|
||||
pass
|
||||
|
||||
def transaction_backend_abort(self):
|
||||
"""
|
||||
Lowlevel interface to the backend transaction.
|
||||
Executes a db ROLLBACK;
|
||||
"""
|
||||
pass
|
||||
|
||||
def transaction_begin(self, transaction):
|
||||
"""
|
||||
Transactions are handled automatically by the db layer.
|
||||
|
6
gramps/gen/lib/place.py
Normal file → Executable file
6
gramps/gen/lib/place.py
Normal file → Executable file
@ -631,9 +631,13 @@ class Place(CitationBase, NoteBase, MediaBase, UrlBase, PrimaryObject):
|
||||
:param acquisition: instance to merge
|
||||
:type acquisition: :class:'~.place.Place
|
||||
"""
|
||||
if acquisition.name and (acquisition.name not in self.alt_names):
|
||||
if acquisition.name.value:
|
||||
if acquisition.name != self.name:
|
||||
if acquisition.name not in self.alt_names:
|
||||
self.alt_names.append(acquisition.name)
|
||||
|
||||
for addendum in acquisition.alt_names:
|
||||
if addendum.value:
|
||||
if addendum != self.name:
|
||||
if addendum not in self.alt_names:
|
||||
self.alt_names.append(addendum)
|
||||
|
6
gramps/gen/lib/placename.py
Normal file → Executable file
6
gramps/gen/lib/placename.py
Normal file → Executable file
@ -199,6 +199,12 @@ class PlaceName(SecondaryObject, DateBase):
|
||||
else:
|
||||
return EQUAL
|
||||
|
||||
def __eq__(self, other):
|
||||
return self.is_equal(other)
|
||||
|
||||
def __ne__(self, other):
|
||||
return not self.is_equal(other)
|
||||
|
||||
def set_value(self, value):
|
||||
"""
|
||||
Set the name for the PlaceName instance.
|
||||
|
32
gramps/gen/lib/test/merge_test.py
Normal file → Executable file
32
gramps/gen/lib/test/merge_test.py
Normal file → Executable file
@ -1389,8 +1389,14 @@ class PlaceCheck(unittest.TestCase, PrivacyBaseTest, MediaBaseTest,
|
||||
def setUp(self):
|
||||
self.phoenix = Place()
|
||||
self.phoenix.set_title('Place 1')
|
||||
self.titanic = Place(self.phoenix)
|
||||
self.ref_obj = Place(self.phoenix)
|
||||
# __init__ copy has bad side effects, don't use it
|
||||
# self.titanic = Place(self.phoenix)
|
||||
self.titanic = Place()
|
||||
self.titanic.set_title('Place 1')
|
||||
# __init__ copy has bad side effects, don't use it
|
||||
# self.ref_obj = Place(self.phoenix)
|
||||
self.ref_obj = Place()
|
||||
self.ref_obj.set_title('Place 1')
|
||||
self.amsterdam = PlaceName()
|
||||
self.amsterdam.set_value('Amsterdam')
|
||||
self.rotterdam = PlaceName()
|
||||
@ -1433,9 +1439,11 @@ class PlaceCheck(unittest.TestCase, PrivacyBaseTest, MediaBaseTest,
|
||||
self.titanic.add_alternative_name(self.leiden)
|
||||
self.ref_obj.set_name(self.amsterdam)
|
||||
self.ref_obj.set_type(PlaceType.CITY)
|
||||
self.ref_obj.add_alternative_name(self.amsterdam)
|
||||
self.ref_obj.add_alternative_name(self.rotterdam)
|
||||
# Base name shouldn't be in alt_names list
|
||||
# self.ref_obj.add_alternative_name(self.amsterdam)
|
||||
# alt_names must be in correct order for test to pass
|
||||
self.ref_obj.add_alternative_name(self.utrecht)
|
||||
self.ref_obj.add_alternative_name(self.rotterdam)
|
||||
self.ref_obj.add_alternative_name(self.leiden)
|
||||
self.phoenix.merge(self.titanic)
|
||||
self.assertEqual(self.phoenix.serialize(), self.ref_obj.serialize())
|
||||
@ -1496,6 +1504,22 @@ class PlaceCheck(unittest.TestCase, PrivacyBaseTest, MediaBaseTest,
|
||||
self.phoenix.merge(self.titanic)
|
||||
self.assertEqual(self.phoenix.serialize(), self.ref_obj.serialize())
|
||||
|
||||
def test_merge_empty(self):
|
||||
self.phoenix.set_name(self.amsterdam)
|
||||
self.phoenix.set_type(PlaceType.CITY)
|
||||
self.phoenix.add_alternative_name(self.rotterdam)
|
||||
self.titanic.set_title('Place 2')
|
||||
# titanic gets empty name
|
||||
self.titanic.set_type(PlaceType.CITY)
|
||||
self.titanic.add_alternative_name(self.utrecht)
|
||||
self.titanic.add_alternative_name(PlaceName()) # empty alt_name
|
||||
self.ref_obj.set_name(self.amsterdam)
|
||||
self.ref_obj.set_type(PlaceType.CITY)
|
||||
self.ref_obj.add_alternative_name(self.rotterdam)
|
||||
self.ref_obj.add_alternative_name(self.utrecht)
|
||||
self.phoenix.merge(self.titanic)
|
||||
self.assertEqual(self.phoenix.serialize(), self.ref_obj.serialize())
|
||||
|
||||
class RepoCheck(unittest.TestCase, PrivacyBaseTest, NoteBaseTest, UrlBaseTest):
|
||||
def setUp(self):
|
||||
self.phoenix = Repository()
|
||||
|
@ -329,6 +329,27 @@ class DBAPI(DbGeneric):
|
||||
def close_backend(self):
|
||||
self.dbapi.close()
|
||||
|
||||
def transaction_backend_begin(self):
|
||||
"""
|
||||
Lowlevel interface to the backend transaction.
|
||||
Executes a db BEGIN;
|
||||
"""
|
||||
self.dbapi.begin()
|
||||
|
||||
def transaction_backend_commit(self):
|
||||
"""
|
||||
Lowlevel interface to the backend transaction.
|
||||
Executes a db END;
|
||||
"""
|
||||
self.dbapi.commit()
|
||||
|
||||
def transaction_backend_abort(self):
|
||||
"""
|
||||
Lowlevel interface to the backend transaction.
|
||||
Executes a db ROLLBACK;
|
||||
"""
|
||||
self.dbapi.rollback()
|
||||
|
||||
def transaction_begin(self, transaction):
|
||||
"""
|
||||
Transactions are handled automatically by the db layer.
|
||||
@ -579,6 +600,7 @@ class DBAPI(DbGeneric):
|
||||
def commit_person(self, person, trans, change_time=None):
|
||||
emit = None
|
||||
old_person = None
|
||||
person.change = int(change_time or time.time())
|
||||
if person.handle in self.person_map:
|
||||
emit = "person-update"
|
||||
old_person = self.get_person_from_handle(person.handle)
|
||||
@ -670,6 +692,7 @@ class DBAPI(DbGeneric):
|
||||
def commit_family(self, family, trans, change_time=None):
|
||||
emit = None
|
||||
old_family = None
|
||||
family.change = int(change_time or time.time())
|
||||
if family.handle in self.family_map:
|
||||
emit = "family-update"
|
||||
old_family = self.get_family_from_handle(family.handle).serialize()
|
||||
@ -733,6 +756,7 @@ class DBAPI(DbGeneric):
|
||||
def commit_citation(self, citation, trans, change_time=None):
|
||||
emit = None
|
||||
old_citation = None
|
||||
citation.change = int(change_time or time.time())
|
||||
if citation.handle in self.citation_map:
|
||||
emit = "citation-update"
|
||||
old_citation = self.get_citation_from_handle(citation.handle).serialize()
|
||||
@ -778,6 +802,7 @@ class DBAPI(DbGeneric):
|
||||
def commit_source(self, source, trans, change_time=None):
|
||||
emit = None
|
||||
old_source = None
|
||||
source.change = int(change_time or time.time())
|
||||
if source.handle in self.source_map:
|
||||
emit = "source-update"
|
||||
old_source = self.get_source_from_handle(source.handle).serialize()
|
||||
@ -825,6 +850,7 @@ class DBAPI(DbGeneric):
|
||||
def commit_repository(self, repository, trans, change_time=None):
|
||||
emit = None
|
||||
old_repository = None
|
||||
repository.change = int(change_time or time.time())
|
||||
if repository.handle in self.repository_map:
|
||||
emit = "repository-update"
|
||||
old_repository = self.get_repository_from_handle(repository.handle).serialize()
|
||||
@ -860,6 +886,7 @@ class DBAPI(DbGeneric):
|
||||
def commit_note(self, note, trans, change_time=None):
|
||||
emit = None
|
||||
old_note = None
|
||||
note.change = int(change_time or time.time())
|
||||
if note.handle in self.note_map:
|
||||
emit = "note-update"
|
||||
old_note = self.get_note_from_handle(note.handle).serialize()
|
||||
@ -892,6 +919,7 @@ class DBAPI(DbGeneric):
|
||||
def commit_place(self, place, trans, change_time=None):
|
||||
emit = None
|
||||
old_place = None
|
||||
place.change = int(change_time or time.time())
|
||||
if place.handle in self.place_map:
|
||||
emit = "place-update"
|
||||
old_place = self.get_place_from_handle(place.handle).serialize()
|
||||
@ -938,6 +966,7 @@ class DBAPI(DbGeneric):
|
||||
def commit_event(self, event, trans, change_time=None):
|
||||
emit = None
|
||||
old_event = None
|
||||
event.change = int(change_time or time.time())
|
||||
if event.handle in self.event_map:
|
||||
emit = "event-update"
|
||||
old_event = self.get_event_from_handle(event.handle).serialize()
|
||||
@ -979,6 +1008,7 @@ class DBAPI(DbGeneric):
|
||||
|
||||
def commit_tag(self, tag, trans, change_time=None):
|
||||
emit = None
|
||||
tag.change = int(change_time or time.time())
|
||||
if tag.handle in self.tag_map:
|
||||
emit = "tag-update"
|
||||
self.dbapi.execute("""UPDATE tag SET blob_data = ?,
|
||||
@ -1004,6 +1034,7 @@ class DBAPI(DbGeneric):
|
||||
def commit_media(self, media, trans, change_time=None):
|
||||
emit = None
|
||||
old_media = None
|
||||
media.change = int(change_time or time.time())
|
||||
if media.handle in self.media_map:
|
||||
emit = "media-update"
|
||||
old_media = self.get_media_from_handle(media.handle).serialize()
|
||||
|
@ -31,6 +31,7 @@ class MySQL:
|
||||
query = query.replace("REAL", "DOUBLE")
|
||||
query = query.replace("change", "change_")
|
||||
query = query.replace("desc", "desc_")
|
||||
query = query.replace(" long ", " long_ ")
|
||||
## LIMIT offset, count
|
||||
## count can be -1, for all
|
||||
## LIMIT -1
|
||||
|
@ -1705,8 +1705,6 @@ class PlaceParser:
|
||||
loc.get_state(),
|
||||
loc.get_country())
|
||||
|
||||
place_import.store_location(location, place.handle)
|
||||
|
||||
for level, name in enumerate(location):
|
||||
if name:
|
||||
break
|
||||
@ -1720,6 +1718,10 @@ class PlaceParser:
|
||||
place.set_type(PlaceType(type_num))
|
||||
code = loc.get_postal_code()
|
||||
place.set_code(code)
|
||||
if place.handle: # if handle is available, store immediately
|
||||
place_import.store_location(location, place.handle)
|
||||
else: # return for storage later
|
||||
return location
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
@ -2954,15 +2956,22 @@ class GedcomParser(UpdateCallback):
|
||||
sub_state.place.get_placeref_list())
|
||||
if place is None:
|
||||
place = sub_state.place
|
||||
place_title = place_displayer.display(self.dbase, place)
|
||||
location = sub_state.pf.load_place(self.place_import, place, place_title)
|
||||
self.dbase.add_place(place, self.trans)
|
||||
# if 'location was created, then store it, now that we have a handle.
|
||||
if location:
|
||||
self.place_import.store_location(location, place.handle)
|
||||
self.place_names[place.get_title()].append(place.get_handle())
|
||||
event.set_place_handle(place.get_handle())
|
||||
else:
|
||||
place.merge(sub_state.place)
|
||||
self.dbase.commit_place(place, self.trans)
|
||||
event.set_place_handle(place.get_handle())
|
||||
place_title = place_displayer.display(self.dbase, place)
|
||||
sub_state.pf.load_place(self.place_import, place, place_title)
|
||||
location = sub_state.pf.load_place(self.place_import, place, place_title)
|
||||
self.dbase.commit_place(place, self.trans)
|
||||
if location:
|
||||
self.place_import.store_location(location, place.handle)
|
||||
event.set_place_handle(place.get_handle())
|
||||
|
||||
def __find_file(self, fullname, altpath):
|
||||
tries = []
|
||||
@ -3319,15 +3328,19 @@ class GedcomParser(UpdateCallback):
|
||||
If just ADR1, ADR2, CITY, STAE, POST or CTRY are provided (this is not
|
||||
actually legal GEDCOM symtax, but may be possible by GEDCOM extensions)
|
||||
then just the structrued address is used.
|
||||
The routine returns a string suitable for a title.
|
||||
"""
|
||||
title = ''
|
||||
free_form_address = free_form_address.replace('\n', ', ')
|
||||
if not (addr.get_street() or addr.get_locality() or
|
||||
addr.get_city() or addr.get_state() or
|
||||
addr.get_postal_code()):
|
||||
|
||||
addr.set_street(free_form_address)
|
||||
return free_form_address
|
||||
else:
|
||||
# structured address provided
|
||||
addr_list = free_form_address.split("\n")
|
||||
addr_list = free_form_address.split(",")
|
||||
str_list = []
|
||||
for func in (addr.get_street(), addr.get_locality(),
|
||||
addr.get_city(), addr.get_state(),
|
||||
@ -3341,6 +3354,13 @@ class GedcomParser(UpdateCallback):
|
||||
self.__add_msg(_("ADDR element ignored '%s'"
|
||||
% elmn), line, state)
|
||||
# The free-form address ADDR is discarded
|
||||
# Assemble a title out of structured address
|
||||
for elmn in str_list:
|
||||
if elmn:
|
||||
if title != '':
|
||||
title += ', '
|
||||
title += elmn
|
||||
return title
|
||||
|
||||
def __parse_trailer(self):
|
||||
"""
|
||||
@ -5395,7 +5415,7 @@ class GedcomParser(UpdateCallback):
|
||||
place = state.place
|
||||
if place:
|
||||
# We encounter a PLAC, having previously encountered an ADDR
|
||||
if place.get_title() and place.get_title() != "":
|
||||
if state.place.place_type.string != _("Address"):
|
||||
# We have previously found a PLAC
|
||||
self.__add_msg(_("A second PLAC ignored"), line, state)
|
||||
# ignore this second PLAC, and use the old one
|
||||
@ -5419,6 +5439,8 @@ class GedcomParser(UpdateCallback):
|
||||
state.msg += sub_state.msg
|
||||
if sub_state.pf: # if we found local PLAC:FORM
|
||||
state.pf = sub_state.pf # save to override global value
|
||||
# merge notes etc into place
|
||||
state.place.merge(sub_state.place)
|
||||
|
||||
def __event_place_note(self, line, state):
|
||||
"""
|
||||
@ -5525,7 +5547,7 @@ class GedcomParser(UpdateCallback):
|
||||
self.__parse_level(sub_state, self.parse_loc_tbl, self.__undefined)
|
||||
state.msg += sub_state.msg
|
||||
|
||||
self.__merge_address(free_form, sub_state.location, line, state)
|
||||
title = self.__merge_address(free_form, sub_state.location, line, state)
|
||||
|
||||
location = sub_state.location
|
||||
|
||||
@ -5572,9 +5594,12 @@ class GedcomParser(UpdateCallback):
|
||||
state.place = Place()
|
||||
place = state.place
|
||||
place.add_alternate_locations(location)
|
||||
place.set_name(PlaceName(value=title))
|
||||
place.set_title(title)
|
||||
place.set_type((PlaceType.CUSTOM, _("Address")))
|
||||
|
||||
# merge notes etc into place
|
||||
place.merge(sub_state.place)
|
||||
state.place.merge(sub_state.place)
|
||||
|
||||
def __add_location(self, place, location):
|
||||
"""
|
||||
|
Loading…
x
Reference in New Issue
Block a user