* src/Relationship.py: many improvements and bug fixes
	* src/plugins/all_relations.py: bug fixes
	* src/plugins/RelCalc.py: use new API
	* src/plugins/rel_nl.py: finished, removed comment
	* src/plugins/rel_it.py: finished
	* src/plugins/rel_pl.py: move old code here away from Relationship
	* src/plugins/rel_pt.py: import gen.lib



svn: r9367
This commit is contained in:
Benny Malengier
2007-11-18 23:39:14 +00:00
parent 690b0bdb3c
commit 3438c8973d
8 changed files with 611 additions and 194 deletions

View File

@ -616,32 +616,6 @@ class RelationshipCalculator:
orig.get_gender(), other.get_gender())
else:
return None
def __apply_filter_old(self, db, person, rel_str, plist, pmap, depth=1):
""" DEPRECATED -- DO NOT USE
"""
if person == None or depth > MAX_DEPTH:
return
depth += 1
plist.append(person.handle)
pmap[person.handle] = rel_str # ?? this overwrites if person is double!
family_handle = person.get_main_parents_family_handle()
try:
if family_handle:
family = db.get_family_from_handle(family_handle)
fhandle = family.father_handle
if fhandle:
father = db.get_person_from_handle(fhandle)
self.__apply_filter_old(db, father, rel_str+'f', plist, pmap,
depth)
mhandle = family.mother_handle
if mhandle:
mother = db.get_person_from_handle(mhandle)
self.__apply_filter_old(db, mother, rel_str+'m', plist, pmap,
depth)
except:
return
def get_relationship_distance(self, db, orig_person, other_person):
"""
@ -759,6 +733,7 @@ class RelationshipCalculator:
self.__all_families = all_families
self.__all_dist = all_dist
self.__only_birth = only_birth
self.__crosslinks = False # no crosslinks
firstRel = -1
secondRel = -1
@ -776,10 +751,7 @@ class RelationshipCalculator:
try:
self.__apply_filter(db, orig_person, '', [], firstMap)
self.__apply_filter(db, other_person, '', [], secondMap,
stoprecursemap = firstMap,
store_all=False)
## print firstMap
## print secondMap
stoprecursemap = firstMap)
except RuntimeError:
return (-1,None,-1,[],-1,[] ) , \
[_("Relationship loop detected")] + self.__msg
@ -788,15 +760,15 @@ class RelationshipCalculator:
if firstMap.has_key(person_handle) :
com = []
#a common ancestor
for rel1,fam1 in zip(firstMap[person_handle][0],
for rel1, fam1 in zip(firstMap[person_handle][0],
firstMap[person_handle][1]):
l1 = len(rel1)
for rel2,fam2 in zip(secondMap[person_handle][0],
for rel2, fam2 in zip(secondMap[person_handle][0],
secondMap[person_handle][1]):
l2 = len(rel2)
#collect paths to arrive at common ancestor
com.append((l1+l2,person_handle,rel1,fam1,
rel2,fam2))
com.append((l1+l2, person_handle, rel1, fam1,
rel2, fam2))
#insert common ancestor in correct position,
# if shorter links, check if not subset
# if longer links, check if not superset
@ -828,7 +800,7 @@ class RelationshipCalculator:
if rel1new == rel1[:len(rel1new)] and \
rel2new == rel2[:len(rel2new)] :
deletelist.append(index)
index += 1
index += 1
deletelist.reverse()
for index in deletelist:
del common[index]
@ -837,8 +809,6 @@ class RelationshipCalculator:
self.__msg += [_('Family tree reaches back more than the maximum '
'%d generations searched.\nIt is possible that '
'relationships have been missed') % (max_depth)]
## print 'common list :', common
if common and not self.__all_dist :
rank = common[0][0]
@ -859,13 +829,18 @@ class RelationshipCalculator:
return [(-1,None,'',[],'',[])], self.__msg
def __apply_filter(self, db, person, rel_str, rel_fam, pmap,
depth=1, stoprecursemap=None, store_all=True):
'''We recursively add parents of person in pmap with correct rel_str,
if store_all. If store_all false, only store parents if in the
stoprecursemap.
Stop recursion if parent is in the stoprecursemap (no need to
look parents of otherpers if done so already for origpers)
store pers
depth=1, stoprecursemap=None):
'''Typically this method is called recursively in two ways:
First method is stoprecursemap= None
In this case a recursemap is builded by storing all data.
Second method is with a stoprecursemap given
In this case parents are recursively looked up. If present in
stoprecursemap, a common ancestor is found, and the method can
stop looking further. If however self.__crosslinks == True, the data
of first contains loops, and parents
will be looked up anyway an stored if common. At end the doubles
are filtered out
'''
if person == None or not person.handle :
return
@ -878,14 +853,20 @@ class RelationshipCalculator:
depth += 1
commonancestor = False
if stoprecursemap and stoprecursemap.has_key(person.handle) :
commonancestor = True
store = True #normally we store all parents
if stoprecursemap:
store = False #but not if a stop map given
if stoprecursemap.has_key(person.handle):
commonancestor = True
store = True
#add person to the map, take into account that person can be obtained
#from different sides
if pmap.has_key(person.handle) :
if pmap.has_key(person.handle):
#person is already a grandparent in another branch, we already have
# had lookup of all parents
# had lookup of all parents, we call that a crosslink
if not stoprecursemap:
self.__crosslinks = True
pmap[person.handle][0] += [rel_str]
pmap[person.handle][1] += [rel_fam]
#check if there is no loop father son of his son, ...
@ -901,29 +882,28 @@ class RelationshipCalculator:
(person.get_primary_name().get_name(),
rel2[len(rel1):])]
return
elif store_all or commonancestor:
elif store:
pmap[person.handle] = [[rel_str],[rel_fam]]
#having added person to the pmap, we only look up recursively to
# parents if this person is not common relative
if commonancestor :
## print 'common ancestor found'
# if however the first map has crosslinks, we need to continue reduced
if commonancestor and not self.__crosslinks :
#don't continue search, great speedup!
return
family_handles = []
main = person.get_main_parents_family_handle()
## print 'main',main
if main :
family_handles = [main]
if self.__all_families :
family_handles = person.get_parent_family_handle_list()
## print 'all_families', family_handles
family_handles = person.get_parent_family_handle_list()
try:
parentstodo = {}
fam = 0
for family_handle in family_handles :
rel_fam_new = rel_fam +[fam]
rel_fam_new = rel_fam + [fam]
family = db.get_family_from_handle(family_handle)
#obtain childref for this person
childrel = [(ref.get_mother_relation(),
@ -982,8 +962,7 @@ class RelationshipCalculator:
data = parentstodo[handle]
self.__apply_filter(db, data[0],
data[1], data[2],
pmap, depth, stoprecursemap, store_all)
pmap, depth, stoprecursemap)
except:
import traceback
print traceback.print_exc()
@ -1021,11 +1000,13 @@ class RelationshipCalculator:
relfamfirst = relation[3][:]
relfamsec = relation[5][:]
#handle pure sibling:
rela2 = relation[2]
rela4 = relation[4]
if relation[2] and relation[2][-1] == self.REL_SIBLING:
#sibling will be the unique common ancestor,
#change to a family with unknown handle for common ancestor
relation[2] = relation[2][:-1] + self.REL_FAM_BIRTH
relation[4] = relation[4] + self.REL_FAM_BIRTH
rela2 = relation[2][:-1] + self.REL_FAM_BIRTH
rela4 = relation[4] + self.REL_FAM_BIRTH
relfamsec = relfamsec + [relfamfirst[-1]]
relstrsec = relation[4][:-1]
commonhandle = []
@ -1052,7 +1033,6 @@ class RelationshipCalculator:
else:
familypaths.append((relstrfirst, relstrsec,
relfamfirst, relfamsec))
##print 'resulting fam path', familypaths
for familypath in familypaths:
#familypath = (relstrfirst, relstrsec, relfamfirst, relfamsec)
try:
@ -1062,28 +1042,58 @@ class RelationshipCalculator:
#if relstr is '', the ancestor is unique, if posfam None,
# first time we see this family path
if (posfam is not None and relstrfirst is not None and
relstrsec is not None):
relstrsec is not None):
#we already have a common ancestor of this family, just add the
#other, setting correct family relation
tmp = commonnew[posfam]
frstcomstr = relation[2][-1]
frstcomstr = rela2[-1]
scndcomstr = tmp[2][-1]
newcomstra = self.famrel_from_persrel(frstcomstr, scndcomstr)
frstcomstr = relation[4][-1]
frstcomstr = rela4[-1]
scndcomstr = tmp[4][-1]
newcomstrb = self.famrel_from_persrel(frstcomstr, scndcomstr)
commonnew[posfam] = (tmp[0], tmp[1]+commonhandle,
relation[2][:-1]+newcomstra,
tmp[3], relation[4][:-1]+newcomstrb,
rela2[:-1]+newcomstra,
tmp[3], rela4[:-1]+newcomstrb,
tmp[5])
else :
existing_path.append(familypath)
commonnew.append((relation[0], commonhandle, relation[2],
relfamfirst, relation[4], relfamsec)
)
##print 'commonnew', commonnew
return commonnew
commonnew.append((relation[0], commonhandle, rela2,
familypath[2], rela4, familypath[3])
)
#we now have multiple person handles, single families, now collapse
# families again if all else equal
collapsed = commonnew[:1]
for rel in commonnew[1:]:
found = False
for newrel in collapsed:
if newrel[0:3] == rel[0:3] and newrel[4] == rel[4]:
#another familypath to arrive at same result, merge
path1 = []
path2 = []
for a, b in zip(newrel[3], rel[3]):
if a == b:
path1.append(a)
elif isinstance(a, list):
path1.append(a.append(b))
else:
path1.append([a, b])
for a, b in zip(newrel[5], rel[5]):
if a == b:
path2.append(a)
elif isinstance(a, list):
path2.append(a.append(b))
else:
path2.append([a, b])
newrel[3][:] = path1[:]
newrel[5][:] = path2[:]
found = True
break
if not found:
collapsed.append(rel)
return collapsed
def famrel_from_persrel(self, persrela, persrelb):
""" Conversion from eg 'f' and 'm' to 'a', so relation to the two
@ -1161,8 +1171,9 @@ class RelationshipCalculator:
return ('', -1, -1)
else:
return ''
data = self.collapse_relations(data)
#most relevant relationship is a birth family relation of lowest rank
databest = [data[0]]
rankbest = data[0][0]
@ -1248,7 +1259,73 @@ class RelationshipCalculator:
return (rel_str, dist_orig, dist_other)
else:
return rel_str
def get_all_relationships(self, db, orig_person, other_person):
""" Returns a tuple, of which the first entry is a list with all
relationships in text, and the second a list of lists of all common
ancestors that have that text as relationship
"""
relstrings = []
commons = {}
if orig_person == None:
return ([], [])
if orig_person.get_handle() == other_person.get_handle():
return ([], [])
is_spouse = self.is_spouse(db, orig_person, other_person)
if is_spouse:
relstrings.append(is_spouse)
commons[is_spouse] = []
data, msg = self.get_relationship_distance_new(
db, orig_person, other_person,
all_dist=True,
all_families=True, only_birth=False)
if not data[0][0] == -1:
for rel in data :
rel2 = rel[2]
rel4 = rel[4]
rel1 = rel[1]
dist_orig = len(rel[2])
dist_other= len(rel[4])
if rel[2] and rel[2][-1] == self.REL_SIBLING:
rel2 = rel2[:-1] + self.REL_FAM_BIRTH
dist_other += 1
rel4 = rel4 + self.REL_FAM_BIRTH
rel1 = None
birth = self.only_birth(rel2) and self.only_birth(rel4)
if dist_orig == 1 and dist_other == 1:
rel_str = self.get_sibling_relationship_string(
self.get_sibling_type(
db, orig_person, other_person),
orig_person.get_gender(),
other_person.get_gender())
else:
rel_str = self.get_single_relationship_string(dist_orig,
dist_other,
orig_person.get_gender(),
other_person.get_gender(),
rel2, rel4,
only_birth=birth,
in_law_a=False,
in_law_b=False)
if not rel_str in relstrings:
relstrings.append(rel_str)
if rel1:
commons[rel_str] = [rel1]
else:
#unknown parent eg
commons[rel_str] = []
else:
if rel1:
commons[rel_str].append(rel1)
#construct the return tupply, relstrings is ordered on rank automatic
common_list = []
for rel_str in relstrings:
common_list.append(commons[rel_str])
return (relstrings, common_list)
def get_relationship(self, db, orig_person, other_person):
"""
returns a string representing the relationshp between the two people,
@ -1463,8 +1540,6 @@ class RelationshipCalculator:
2/for better determination of siblings, use if Ga=1=Gb
get_sibling_relationship_string
"""
## print 'Ga, Gb :', Ga, Gb
if only_birth:
step = ''
else: