probably_alive and CalcEstDates now share same codebase; rewritten probably_alive
svn: r14102
This commit is contained in:
		
							
								
								
									
										394
									
								
								src/Utils.py
									
									
									
									
									
								
							
							
						
						
									
										394
									
								
								src/Utils.py
									
									
									
									
									
								
							| @@ -452,12 +452,401 @@ def create_uid(self, handle=None): | ||||
|         uid = uuid.uuid4() | ||||
|     return uid.hex.upper() | ||||
|  | ||||
| class ProbablyAlive(object): | ||||
|     """ | ||||
|     An object to hold the parameters for considering someone alive. | ||||
|     """ | ||||
|  | ||||
|     def __init__(self,  | ||||
|                  db, | ||||
|                  max_sib_age_diff,  | ||||
|                  max_age_prob_alive,  | ||||
|                  avg_generation_gap): | ||||
|         self.db = db | ||||
|         self.MAX_SIB_AGE_DIFF = max_sib_age_diff | ||||
|         self.MAX_AGE_PROB_ALIVE = max_age_prob_alive | ||||
|         self.AVG_GENERATION_GAP = avg_generation_gap | ||||
|  | ||||
|     def probably_alive_range(self, person, is_spouse=False): | ||||
|         if person is None: | ||||
|             return (None, None, "", None) | ||||
|         birth_ref = person.get_birth_ref() | ||||
|         death_ref = person.get_death_ref() | ||||
|         death_date = None | ||||
|         birth_date = None | ||||
|         explain = "" | ||||
|         # If the recorded death year is before current year then | ||||
|         # things are simple. | ||||
|         if death_ref and death_ref.get_role().is_primary(): | ||||
|             death = self.db.get_event_from_handle(death_ref.ref) | ||||
|             if death and death.get_date_object().get_start_date() != gen.lib.Date.EMPTY: | ||||
|                 death_date = death.get_date_object() | ||||
|  | ||||
|         # Look for Cause Of Death, Burial or Cremation events. | ||||
|         # These are fairly good indications that someone's not alive. | ||||
|         if not death_date: | ||||
|             for ev_ref in person.get_primary_event_ref_list(): | ||||
|                 ev = self.db.get_event_from_handle(ev_ref.ref) | ||||
|                 if ev and ev.type.is_death_fallback(): | ||||
|                     death_date = ev.get_date_object() | ||||
|                     explain = _("death-related evidence") | ||||
|  | ||||
|         # If they were born within X years before current year then | ||||
|         # assume they are alive (we already know they are not dead). | ||||
|         if not birth_date: | ||||
|             if birth_ref and birth_ref.get_role().is_primary(): | ||||
|                 birth = self.db.get_event_from_handle(birth_ref.ref) | ||||
|                 if birth and birth.get_date_object().get_start_date() != gen.lib.Date.EMPTY: | ||||
|                     birth_date = birth.get_date_object() | ||||
|  | ||||
|         # Look for Baptism, etc events. | ||||
|         # These are fairly good indications that someone's birth. | ||||
|         if not birth_date: | ||||
|             for ev_ref in person.get_primary_event_ref_list(): | ||||
|                 ev = self.db.get_event_from_handle(ev_ref.ref) | ||||
|                 if ev and ev.type.is_birth_fallback(): | ||||
|                     birth_date = ev.get_date_object() | ||||
|                     explain = _("birth-related evidence") | ||||
|  | ||||
|         if not birth_date and death_date: | ||||
|             # person died more than MAX after current year | ||||
|             birth_date = death_date.copy_offset_ymd(year=-self.MAX_AGE_PROB_ALIVE) | ||||
|             explain = _("death date") | ||||
|          | ||||
|         if not death_date and birth_date: | ||||
|             # person died more than MAX after current year | ||||
|             death_date = birth_date.copy_offset_ymd(year=self.MAX_AGE_PROB_ALIVE) | ||||
|             explain = _("birth date") | ||||
|          | ||||
|         if death_date and birth_date: | ||||
|             return (birth_date, death_date, explain, "") # direct self evidence | ||||
|          | ||||
|         # Neither birth nor death events are available. Try looking | ||||
|         # at siblings. If a sibling was born more than X years past,  | ||||
|         # or more than Z future, then probably this person is | ||||
|         # not alive. If the sibling died more than X years | ||||
|         # past, or more than X years future, then probably not alive. | ||||
|  | ||||
|         family_list = person.get_parent_family_handle_list() | ||||
|         for family_handle in family_list: | ||||
|             family = self.db.get_family_from_handle(family_handle) | ||||
|             for child_ref in family.get_child_ref_list(): | ||||
|                 child_handle = child_ref.ref | ||||
|                 child = self.db.get_person_from_handle(child_handle) | ||||
|                 # Go through once looking for direct evidence: | ||||
|                 for ev_ref in child.get_primary_event_ref_list(): | ||||
|                     ev = self.db.get_event_from_handle(ev_ref.ref) | ||||
|                     if ev and ev.type.is_birth(): | ||||
|                         dobj = ev.get_date_object()  | ||||
|                         if dobj.get_start_date() != gen.lib.Date.EMPTY: | ||||
|                             # if sibling birth date too far away, then not alive: | ||||
|                             year = dobj.get_year() | ||||
|                             if year != 0: | ||||
|                                 # sibling birth date | ||||
|                                 return (gen.lib.Date().copy_ymd(year - self.MAX_SIB_AGE_DIFF), | ||||
|                                         gen.lib.Date().copy_ymd(year + self.MAX_SIB_AGE_DIFF + self.MAX_AGE_PROB_ALIVE), | ||||
|                                         _("sibling birth date"), | ||||
|                                         child) | ||||
|                     elif ev and ev.type.is_death(): | ||||
|                         dobj = ev.get_date_object()  | ||||
|                         if dobj.get_start_date() != gen.lib.Date.EMPTY: | ||||
|                             # if sibling death date too far away, then not alive: | ||||
|                             year = dobj.get_year() | ||||
|                             if year != 0: | ||||
|                                 # sibling death date | ||||
|                                 return (gen.lib.Date().copy_ymd(year - self.MAX_SIB_AGE_DIFF - self.MAX_AGE_PROB_ALIVE), | ||||
|                                         gen.lib.Date().copy_ymd(year + self.MAX_SIB_AGE_DIFF), | ||||
|                                         _("sibling death date"), | ||||
|                                         child) | ||||
|                 # Go through again looking for fallback: | ||||
|                 for ev_ref in child.get_primary_event_ref_list(): | ||||
|                     ev = self.db.get_event_from_handle(ev_ref.ref) | ||||
|                     if ev and ev.type.is_birth_fallback(): | ||||
|                         dobj = ev.get_date_object()  | ||||
|                         if dobj.get_start_date() != gen.lib.Date.EMPTY: | ||||
|                             # if sibling birth date too far away, then not alive: | ||||
|                             year = dobj.get_year() | ||||
|                             if year != 0: | ||||
|                                 # sibling birth date | ||||
|                                 return (gen.lib.Date().copy_ymd(year - self.MAX_SIB_AGE_DIFF), | ||||
|                                         gen.lib.Date().copy_ymd(year + self.MAX_SIB_AGE_DIFF + self.MAX_AGE_PROB_ALIVE), | ||||
|                                         _("sibling birth-related date"), | ||||
|                                         child) | ||||
|                     elif ev and ev.type.is_death_fallback(): | ||||
|                         dobj = ev.get_date_object()  | ||||
|                         if dobj.get_start_date() != gen.lib.Date.EMPTY: | ||||
|                             # if sibling death date too far away, then not alive: | ||||
|                             year = dobj.get_year() | ||||
|                             if year != 0: | ||||
|                                 # sibling death date | ||||
|                                 return (gen.lib.Date().copy_ymd(year - self.MAX_SIB_AGE_DIFF - self.MAX_AGE_PROB_ALIVE), | ||||
|                                         gen.lib.Date().copy_ymd(year + self.MAX_SIB_AGE_DIFF), | ||||
|                                         _("sibling death-related date"), | ||||
|                                         child) | ||||
|  | ||||
|         if not is_spouse: # if you are not in recursion, let's recurse: | ||||
|             for family_handle in person.get_family_handle_list(): | ||||
|                 family = self.db.get_family_from_handle(family_handle) | ||||
|                 if family: | ||||
|                     mother_handle = family.get_mother_handle() | ||||
|                     father_handle = family.get_father_handle() | ||||
|                     if mother_handle == person.handle and father_handle: | ||||
|                         father = self.db.get_person_from_handle(father_handle) | ||||
|                         date1, date2, explain, other = self.probably_alive_range(father, is_spouse=True) | ||||
|                         if date1 and date2: | ||||
|                             return date1, date2, _("a spouse, ") + explain, other | ||||
|                     elif father_handle == person.handle and mother_handle: | ||||
|                         mother = self.db.get_person_from_handle(mother_handle) | ||||
|                         date1, date2, explain, other = self.probably_alive_range(mother, is_spouse=True) | ||||
|                         if date1 and date2: | ||||
|                             return date1, date2, _("a spouse, ") + explain, other | ||||
|  | ||||
|         # Try looking for descendants that were born more than a lifespan | ||||
|         # ago. | ||||
|  | ||||
|         def descendants_too_old (person, years): | ||||
|             for family_handle in person.get_family_handle_list(): | ||||
|                 family = self.db.get_family_from_handle(family_handle) | ||||
|                 for child_ref in family.get_child_ref_list(): | ||||
|                     child_handle = child_ref.ref | ||||
|                     child = self.db.get_person_from_handle(child_handle) | ||||
|                     child_birth_ref = child.get_birth_ref() | ||||
|                     if child_birth_ref: | ||||
|                         child_birth = self.db.get_event_from_handle(child_birth_ref.ref) | ||||
|                         dobj = child_birth.get_date_object() | ||||
|                         if dobj.get_start_date() != gen.lib.Date.EMPTY: | ||||
|                             d = gen.lib.Date(dobj) | ||||
|                             val = d.get_start_date() | ||||
|                             val = d.get_year() - years | ||||
|                             d.set_year(val) | ||||
|                             return (d, d.copy_offset_ymd(self.MAX_AGE_PROB_ALIVE), | ||||
|                                     _("descendent birth date"), | ||||
|                                     child) | ||||
|                     child_death_ref = child.get_death_ref() | ||||
|                     if child_death_ref: | ||||
|                         child_death = self.db.get_event_from_handle(child_death_ref.ref) | ||||
|                         dobj = child_death.get_date_object() | ||||
|                         if dobj.get_start_date() != gen.lib.Date.EMPTY: | ||||
|                             return (dobj.copy_offset_ymd(- self.AVG_GENERATION_GAP),  | ||||
|                                     dobj.copy_offset_ymd(- self.AVG_GENERATION_GAP + self.MAX_AGE_PROB_ALIVE), | ||||
|                                     _("descendent death date"), | ||||
|                                     child) | ||||
|                     date1, date2, explain, other = descendants_too_old (child, years + self.AVG_GENERATION_GAP) | ||||
|                     if date1 and date2: | ||||
|                         return date1, date2, explain, other | ||||
|                     # Check fallback data: | ||||
|                     for ev_ref in child.get_primary_event_ref_list(): | ||||
|                         ev = self.db.get_event_from_handle(ev_ref.ref) | ||||
|                         if ev and ev.type.is_birth_fallback(): | ||||
|                             dobj = ev.get_date_object()  | ||||
|                             if dobj.get_start_date() != gen.lib.Date.EMPTY: | ||||
|                                 d = gen.lib.Date(dobj) | ||||
|                                 val = d.get_start_date() | ||||
|                                 val = d.get_year() - years | ||||
|                                 d.set_year(val) | ||||
|                                 return (d, d.copy_offset_ymd(self.MAX_AGE_PROB_ALIVE), | ||||
|                                         _("descendent birth-related date"), | ||||
|                                         child) | ||||
|  | ||||
|                         elif ev and ev.type.is_death_fallback(): | ||||
|                             dobj = ev.get_date_object()  | ||||
|                             if dobj.get_start_date() != gen.lib.Date.EMPTY: | ||||
|                                 return (dobj.copy_offset_ymd(- self.AVG_GENERATION_GAP),  | ||||
|                                         dobj.copy_offset_ymd(- self.AVG_GENERATION_GAP + self.MAX_AGE_PROB_ALIVE), | ||||
|                                         _("descendent death-related date"), | ||||
|                                         child) | ||||
|  | ||||
|             return (None, None, "", None) | ||||
|  | ||||
|         # If there are descendants that are too old for the person to have | ||||
|         # been alive in the current year then they must be dead. | ||||
|  | ||||
|         date1, date2, explain, other = None, None, "", None | ||||
|         try: | ||||
|             date1, date2, explain, other = descendants_too_old(person, self.AVG_GENERATION_GAP) | ||||
|         except RuntimeError: | ||||
|             raise Errors.DatabaseError( | ||||
|                 _("Database error: %s is defined as his or her own ancestor") % | ||||
|                 name_displayer.display(person)) | ||||
|  | ||||
|         if date1 and date2: | ||||
|             return (date1, date2, explain, other) | ||||
|  | ||||
|         def ancestors_too_old(person, year): | ||||
|             family_handle = person.get_main_parents_family_handle() | ||||
|             if family_handle:                 | ||||
|                 family = self.db.get_family_from_handle(family_handle) | ||||
|                 father_handle = family.get_father_handle() | ||||
|                 if father_handle: | ||||
|                     father = self.db.get_person_from_handle(father_handle) | ||||
|                     father_birth_ref = father.get_birth_ref() | ||||
|                     if father_birth_ref and father_birth_ref.get_role().is_primary(): | ||||
|                         father_birth = self.db.get_event_from_handle( | ||||
|                             father_birth_ref.ref) | ||||
|                         dobj = father_birth.get_date_object() | ||||
|                         if dobj.get_start_date() != gen.lib.Date.EMPTY: | ||||
|                             return (dobj.copy_offset_ymd(- year),  | ||||
|                                     dobj.copy_offset_ymd(- year + self.MAX_AGE_PROB_ALIVE), | ||||
|                                     _("ancestor birth date"), | ||||
|                                     father) | ||||
|                     father_death_ref = father.get_death_ref() | ||||
|                     if father_death_ref and father_death_ref.get_role().is_primary(): | ||||
|                         father_death = self.db.get_event_from_handle( | ||||
|                             father_death_ref.ref) | ||||
|                         dobj = father_death.get_date_object() | ||||
|                         if dobj.get_start_date() != gen.lib.Date.EMPTY: | ||||
|                             return (dobj.copy_offset_ymd(- year - self.MAX_AGE_PROB_ALIVE),  | ||||
|                                     dobj.copy_offset_ymd(- year - self.MAX_AGE_PROB_ALIVE + self.MAX_AGE_PROB_ALIVE), | ||||
|                                     _("ancestor death date"), | ||||
|                                     father) | ||||
|  | ||||
|                     # Check fallback data: | ||||
|                     for ev_ref in father.get_primary_event_ref_list(): | ||||
|                         ev = self.db.get_event_from_handle(ev_ref.ref) | ||||
|                         if ev and ev.type.is_birth_fallback(): | ||||
|                             dobj = ev.get_date_object()  | ||||
|                             if dobj.get_start_date() != gen.lib.Date.EMPTY: | ||||
|                                 return (dobj.copy_offset_ymd(- year),  | ||||
|                                         dobj.copy_offset_ymd(- year + self.MAX_AGE_PROB_ALIVE), | ||||
|                                         _("ancestor birth-related date"), | ||||
|                                         father) | ||||
|  | ||||
|                         elif ev and ev.type.is_death_fallback(): | ||||
|                             dobj = ev.get_date_object()  | ||||
|                             if dobj.get_start_date() != gen.lib.Date.EMPTY: | ||||
|                                 return (dobj.copy_offset_ymd(- year - self.MAX_AGE_PROB_ALIVE),  | ||||
|                                         dobj.copy_offset_ymd(- year - self.MAX_AGE_PROB_ALIVE + self.MAX_AGE_PROB_ALIVE), | ||||
|                                         _("ancestor death-related date"), | ||||
|                                         father) | ||||
|  | ||||
|                     date1, date2, explain, other = ancestors_too_old (father, year - self.AVG_GENERATION_GAP) | ||||
|                     if date1 and date2: | ||||
|                         return date1, date2, explain, other | ||||
|  | ||||
|                 mother_handle = family.get_mother_handle() | ||||
|                 if mother_handle: | ||||
|                     mother = self.db.get_person_from_handle(mother_handle) | ||||
|                     mother_birth_ref = mother.get_birth_ref() | ||||
|                     if mother_birth_ref and mother_birth_ref.get_role().is_primary(): | ||||
|                         mother_birth = self.db.get_event_from_handle(mother_birth_ref.ref) | ||||
|                         dobj = mother_birth.get_date_object() | ||||
|                         if dobj.get_start_date() != gen.lib.Date.EMPTY: | ||||
|                             return (dobj.copy_offset_ymd(- year),  | ||||
|                                     dobj.copy_offset_ymd(- year + self.MAX_AGE_PROB_ALIVE), | ||||
|                                     _("ancestor birth date"), | ||||
|                                     mother) | ||||
|                     mother_death_ref = mother.get_death_ref() | ||||
|                     if mother_death_ref and mother_death_ref.get_role().is_primary(): | ||||
|                         mother_death = self.db.get_event_from_handle( | ||||
|                             mother_death_ref.ref) | ||||
|                         dobj = mother_death.get_date_object() | ||||
|                         if dobj.get_start_date() != gen.lib.Date.EMPTY: | ||||
|                             return (dobj.copy_offset_ymd(- year - self.MAX_AGE_PROB_ALIVE),  | ||||
|                                     dobj.copy_offset_ymd(- year - self.MAX_AGE_PROB_ALIVE + self.MAX_AGE_PROB_ALIVE), | ||||
|                                     _("ancestor death date"), | ||||
|                                     mother) | ||||
|  | ||||
|                     # Check fallback data: | ||||
|                     for ev_ref in mother.get_primary_event_ref_list(): | ||||
|                         ev = self.db.get_event_from_handle(ev_ref.ref) | ||||
|                         if ev and ev.type.is_birth_fallback(): | ||||
|                             dobj = ev.get_date_object()  | ||||
|                             if dobj.get_start_date() != gen.lib.Date.EMPTY: | ||||
|                                 return (dobj.copy_offset_ymd(- year),  | ||||
|                                         dobj.copy_offset_ymd(- year + self.MAX_AGE_PROB_ALIVE), | ||||
|                                         _("ancestor birth-related date"), | ||||
|                                         mother) | ||||
|  | ||||
|                         elif ev and ev.type.is_death_fallback(): | ||||
|                             dobj = ev.get_date_object()  | ||||
|                             if dobj.get_start_date() != gen.lib.Date.EMPTY: | ||||
|                                 return (dobj.copy_offset_ymd(- year - self.MAX_AGE_PROB_ALIVE),  | ||||
|                                         dobj.copy_offset_ymd(- year - self.MAX_AGE_PROB_ALIVE + self.MAX_AGE_PROB_ALIVE), | ||||
|                                         _("ancestor death-related date"), | ||||
|                                         mother) | ||||
|  | ||||
|                     date1, date2, explain, other = ancestors_too_old (mother, year - self.AVG_GENERATION_GAP) | ||||
|                     if date1 and date2: | ||||
|                         return (date1, date2, explain, other) | ||||
|  | ||||
|             return (None, None, "", None) | ||||
|  | ||||
|         # If there are ancestors that would be too old in the current year | ||||
|         # then assume our person must be dead too. | ||||
|         date1, date2, explain, other = ancestors_too_old (person, - self.AVG_GENERATION_GAP) | ||||
|         if date1 and date2: | ||||
|             return (date1, date2, explain, other) | ||||
|  | ||||
|         # If we can't find any reason to believe that they are dead we | ||||
|         # must assume they are alive. | ||||
|  | ||||
|         return (None, None, "", None) | ||||
|  | ||||
| #------------------------------------------------------------------------- | ||||
| # | ||||
| # probably_alive | ||||
| # | ||||
| #------------------------------------------------------------------------- | ||||
| def probably_alive(person, db, current_date=None, limit=0): | ||||
| def probably_alive(person, db,  | ||||
|                    current_date=None,  | ||||
|                    limit=0, | ||||
|                    max_sib_age_diff=None,  | ||||
|                    max_age_prob_alive=None,  | ||||
|                    avg_generation_gap=None): | ||||
|     """ | ||||
|     Return true if the person may be alive on current_date. | ||||
|  | ||||
|     This works by a process of emlimination. If we can't find a good | ||||
|     reason to believe that someone is dead then we assume they must | ||||
|     be alive. | ||||
|  | ||||
|     :param current_date: a date object that is not estimated or modified | ||||
|                    (defaults to today) | ||||
|     :param limit:  number of years to check beyond death_date | ||||
|     :param max_sib_age_diff: maximum sibling age difference, in years | ||||
|     :param max_age_prob_alive: maximum age of a person, in years | ||||
|     :param avg_generation_gap: average generation gap, in years | ||||
|     """ | ||||
|     if max_sib_age_diff is None: | ||||
|         max_sib_age_diff = _MAX_SIB_AGE_DIFF  | ||||
|     if max_age_prob_alive is None: | ||||
|         max_age_prob_alive = _MAX_AGE_PROB_ALIVE | ||||
|     if avg_generation_gap is None: | ||||
|         avg_generation_gap = _AVG_GENERATION_GAP | ||||
|     pb = ProbablyAlive(db, max_sib_age_diff,  | ||||
|                        max_age_prob_alive, avg_generation_gap) | ||||
|     birth, death, explain, relative = pb.probably_alive_range(person, db) | ||||
|     if death is None: # no evidence... can't say if alive/dead | ||||
|         return True | ||||
|     # must have est dates | ||||
|     if current_date: # date in which to consider alive | ||||
|         # SPECIAL CASE: Today: | ||||
|         if current_date.match(gen.lib.date.Today(), "=="): | ||||
|             if person.get_death_ref(): | ||||
|                 return False | ||||
|         if limit: | ||||
|             death += limit # add these years to death | ||||
|         if death.match(gen.lib.date.Today(), ">"): | ||||
|             return True | ||||
|         result = (current_date.match(birth, ">=") and  | ||||
|                   current_date.match(death, "<=")) | ||||
|         return result | ||||
|     # else, they have a est death date, and no current_date give, thus dead | ||||
|     return False | ||||
|  | ||||
| def probably_alive_range(person, db,  | ||||
|                          max_sib_age_diff=None,  | ||||
|                          max_age_prob_alive=None,  | ||||
|                          avg_generation_gap=None): | ||||
|     """ | ||||
|     Computes estimated birth and death dates. | ||||
|     Returns: (birth_date, death_date, explain_text, related_person) | ||||
|     """ | ||||
|     pb = ProbablyAlive(db, max_sib_age_diff,  | ||||
|                        max_age_prob_alive, avg_generation_gap) | ||||
|     return pb.probably_alive_range(person, db) | ||||
|  | ||||
| def probably_alive_old(person, db, current_date=None, limit=0): | ||||
|     """Return true if the person may be alive on current_date. | ||||
|  | ||||
|     This works by a process of emlimination. If we can't find a good | ||||
| @@ -468,8 +857,7 @@ def probably_alive(person, db, current_date=None, limit=0): | ||||
|                    (defaults to today) | ||||
|     :param limit:  number of years to check beyond death_date | ||||
|     """ | ||||
|     today = gen.lib.Date() | ||||
|     today.set_yr_mon_day(*time.localtime(time.time())[0:3]) | ||||
|     today = gen.lib.date.Today() | ||||
|     if current_date is None: | ||||
|         current_date = today | ||||
|     # Are we checking to see if they are alive right now? | ||||
|   | ||||
| @@ -48,7 +48,7 @@ from ReportBase import ReportUtils | ||||
| from docgen import TextBufDoc | ||||
| from Simple import make_basic_stylesheet, SimpleAccess, SimpleDoc, SimpleTable | ||||
| from QuestionDialog import QuestionDialog | ||||
| from Utils import create_id | ||||
| from Utils import create_id, probably_alive_range | ||||
| import DateHandler | ||||
|  | ||||
| #------------------------------------------------------------------------ | ||||
| @@ -509,317 +509,9 @@ class CalcToolManagedWindow(PluginWindows.ToolManagedWindowBatch): | ||||
|         self.db.add_event(event, self.trans) | ||||
|         return event | ||||
|  | ||||
|     def calc_estimates(self, person, is_spouse=False): | ||||
|         if person is None: | ||||
|             return (None, None, "", None) | ||||
|         birth_ref = person.get_birth_ref() | ||||
|         death_ref = person.get_death_ref() | ||||
|         death_date = None | ||||
|         birth_date = None | ||||
|         explain = "" | ||||
|         # If the recorded death year is before current year then | ||||
|         # things are simple. | ||||
|         if death_ref and death_ref.get_role().is_primary(): | ||||
|             death = self.db.get_event_from_handle(death_ref.ref) | ||||
|             if death and death.get_date_object().get_start_date() != gen.lib.Date.EMPTY: | ||||
|                 death_date = death.get_date_object() | ||||
|     def calc_estimates(self, person): | ||||
|         return probably_alive_range(person, self.db, | ||||
|                          self.MAX_SIB_AGE_DIFF,  | ||||
|                          self.MAX_AGE_PROB_ALIVE,  | ||||
|                          self.AVG_GENERATION_GAP) | ||||
|  | ||||
|         # Look for Cause Of Death, Burial or Cremation events. | ||||
|         # These are fairly good indications that someone's not alive. | ||||
|         if not death_date: | ||||
|             for ev_ref in person.get_primary_event_ref_list(): | ||||
|                 ev = self.db.get_event_from_handle(ev_ref.ref) | ||||
|                 if ev and ev.type.is_death_fallback(): | ||||
|                     death_date = ev.get_date_object() | ||||
|                     explain = _("death-related evidence") | ||||
|  | ||||
|         # If they were born within X years before current year then | ||||
|         # assume they are alive (we already know they are not dead). | ||||
|         if not birth_date: | ||||
|             if birth_ref and birth_ref.get_role().is_primary(): | ||||
|                 birth = self.db.get_event_from_handle(birth_ref.ref) | ||||
|                 if birth and birth.get_date_object().get_start_date() != gen.lib.Date.EMPTY: | ||||
|                     birth_date = birth.get_date_object() | ||||
|  | ||||
|         # Look for Baptism, etc events. | ||||
|         # These are fairly good indications that someone's birth. | ||||
|         if not birth_date: | ||||
|             for ev_ref in person.get_primary_event_ref_list(): | ||||
|                 ev = self.db.get_event_from_handle(ev_ref.ref) | ||||
|                 if ev and ev.type.is_birth_fallback(): | ||||
|                     birth_date = ev.get_date_object() | ||||
|                     explain = _("birth-related evidence") | ||||
|  | ||||
|         if not birth_date and death_date: | ||||
|             # person died more than MAX after current year | ||||
|             birth_date = death_date.copy_offset_ymd(year=-self.MAX_AGE_PROB_ALIVE) | ||||
|             explain = _("death date") | ||||
|          | ||||
|         if not death_date and birth_date: | ||||
|             # person died more than MAX after current year | ||||
|             death_date = birth_date.copy_offset_ymd(year=self.MAX_AGE_PROB_ALIVE) | ||||
|             explain = _("birth date") | ||||
|          | ||||
|         if death_date and birth_date: | ||||
|             return (birth_date, death_date, explain, "") # direct self evidence | ||||
|          | ||||
|         # Neither birth nor death events are available. Try looking | ||||
|         # at siblings. If a sibling was born more than X years past,  | ||||
|         # or more than Z future, then probably this person is | ||||
|         # not alive. If the sibling died more than X years | ||||
|         # past, or more than X years future, then probably not alive. | ||||
|  | ||||
|         family_list = person.get_parent_family_handle_list() | ||||
|         for family_handle in family_list: | ||||
|             family = self.db.get_family_from_handle(family_handle) | ||||
|             for child_ref in family.get_child_ref_list(): | ||||
|                 child_handle = child_ref.ref | ||||
|                 child = self.db.get_person_from_handle(child_handle) | ||||
|                 # Go through once looking for direct evidence: | ||||
|                 for ev_ref in child.get_primary_event_ref_list(): | ||||
|                     ev = self.db.get_event_from_handle(ev_ref.ref) | ||||
|                     if ev and ev.type.is_birth(): | ||||
|                         dobj = ev.get_date_object()  | ||||
|                         if dobj.get_start_date() != gen.lib.Date.EMPTY: | ||||
|                             # if sibling birth date too far away, then not alive: | ||||
|                             year = dobj.get_year() | ||||
|                             if year != 0: | ||||
|                                 # sibling birth date | ||||
|                                 return (gen.lib.Date().copy_ymd(year - self.MAX_SIB_AGE_DIFF), | ||||
|                                         gen.lib.Date().copy_ymd(year + self.MAX_SIB_AGE_DIFF + self.MAX_AGE_PROB_ALIVE), | ||||
|                                         _("sibling birth date"), | ||||
|                                         child) | ||||
|                     elif ev and ev.type.is_death(): | ||||
|                         dobj = ev.get_date_object()  | ||||
|                         if dobj.get_start_date() != gen.lib.Date.EMPTY: | ||||
|                             # if sibling death date too far away, then not alive: | ||||
|                             year = dobj.get_year() | ||||
|                             if year != 0: | ||||
|                                 # sibling death date | ||||
|                                 return (gen.lib.Date().copy_ymd(year - self.MAX_SIB_AGE_DIFF - self.MAX_AGE_PROB_ALIVE), | ||||
|                                         gen.lib.Date().copy_ymd(year + self.MAX_SIB_AGE_DIFF), | ||||
|                                         _("sibling death date"), | ||||
|                                         child) | ||||
|                 # Go through again looking for fallback: | ||||
|                 for ev_ref in child.get_primary_event_ref_list(): | ||||
|                     ev = self.db.get_event_from_handle(ev_ref.ref) | ||||
|                     if ev and ev.type.is_birth_fallback(): | ||||
|                         dobj = ev.get_date_object()  | ||||
|                         if dobj.get_start_date() != gen.lib.Date.EMPTY: | ||||
|                             # if sibling birth date too far away, then not alive: | ||||
|                             year = dobj.get_year() | ||||
|                             if year != 0: | ||||
|                                 # sibling birth date | ||||
|                                 return (gen.lib.Date().copy_ymd(year - self.MAX_SIB_AGE_DIFF), | ||||
|                                         gen.lib.Date().copy_ymd(year + self.MAX_SIB_AGE_DIFF + self.MAX_AGE_PROB_ALIVE), | ||||
|                                         _("sibling birth-related date"), | ||||
|                                         child) | ||||
|                     elif ev and ev.type.is_death_fallback(): | ||||
|                         dobj = ev.get_date_object()  | ||||
|                         if dobj.get_start_date() != gen.lib.Date.EMPTY: | ||||
|                             # if sibling death date too far away, then not alive: | ||||
|                             year = dobj.get_year() | ||||
|                             if year != 0: | ||||
|                                 # sibling death date | ||||
|                                 return (gen.lib.Date().copy_ymd(year - self.MAX_SIB_AGE_DIFF - self.MAX_AGE_PROB_ALIVE), | ||||
|                                         gen.lib.Date().copy_ymd(year + self.MAX_SIB_AGE_DIFF), | ||||
|                                         _("sibling death-related date"), | ||||
|                                         child) | ||||
|  | ||||
|         if not is_spouse: # if you are not in recursion, let's recurse: | ||||
|             for family_handle in person.get_family_handle_list(): | ||||
|                 family = self.db.get_family_from_handle(family_handle) | ||||
|                 if family: | ||||
|                     mother_handle = family.get_mother_handle() | ||||
|                     father_handle = family.get_father_handle() | ||||
|                     if mother_handle == person.handle and father_handle: | ||||
|                         father = self.db.get_person_from_handle(father_handle) | ||||
|                         date1, date2, explain, other = self.calc_estimates(father, is_spouse=True) | ||||
|                         if date1 and date2: | ||||
|                             return date1, date2, _("a spouse, ") + explain, other | ||||
|                     elif father_handle == person.handle and mother_handle: | ||||
|                         mother = self.db.get_person_from_handle(mother_handle) | ||||
|                         date1, date2, explain, other = self.calc_estimates(mother, is_spouse=True) | ||||
|                         if date1 and date2: | ||||
|                             return date1, date2, _("a spouse, ") + explain, other | ||||
|  | ||||
|         # Try looking for descendants that were born more than a lifespan | ||||
|         # ago. | ||||
|  | ||||
|         def descendants_too_old (person, years): | ||||
|             for family_handle in person.get_family_handle_list(): | ||||
|                 family = self.db.get_family_from_handle(family_handle) | ||||
|                 for child_ref in family.get_child_ref_list(): | ||||
|                     child_handle = child_ref.ref | ||||
|                     child = self.db.get_person_from_handle(child_handle) | ||||
|                     child_birth_ref = child.get_birth_ref() | ||||
|                     if child_birth_ref: | ||||
|                         child_birth = self.db.get_event_from_handle(child_birth_ref.ref) | ||||
|                         dobj = child_birth.get_date_object() | ||||
|                         if dobj.get_start_date() != gen.lib.Date.EMPTY: | ||||
|                             d = gen.lib.Date(dobj) | ||||
|                             val = d.get_start_date() | ||||
|                             val = d.get_year() - years | ||||
|                             d.set_year(val) | ||||
|                             return (d, d.copy_offset_ymd(self.MAX_AGE_PROB_ALIVE), | ||||
|                                     _("descendent birth date"), | ||||
|                                     child) | ||||
|                     child_death_ref = child.get_death_ref() | ||||
|                     if child_death_ref: | ||||
|                         child_death = self.db.get_event_from_handle(child_death_ref.ref) | ||||
|                         dobj = child_death.get_date_object() | ||||
|                         if dobj.get_start_date() != gen.lib.Date.EMPTY: | ||||
|                             return (dobj.copy_offset_ymd(- self.AVG_GENERATION_GAP),  | ||||
|                                     dobj.copy_offset_ymd(- self.AVG_GENERATION_GAP + self.MAX_AGE_PROB_ALIVE), | ||||
|                                     _("descendent death date"), | ||||
|                                     child) | ||||
|                     date1, date2, explain, other = descendants_too_old (child, years + self.AVG_GENERATION_GAP) | ||||
|                     if date1 and date2: | ||||
|                         return date1, date2, explain, other | ||||
|                     # Check fallback data: | ||||
|                     for ev_ref in child.get_primary_event_ref_list(): | ||||
|                         ev = self.db.get_event_from_handle(ev_ref.ref) | ||||
|                         if ev and ev.type.is_birth_fallback(): | ||||
|                             dobj = ev.get_date_object()  | ||||
|                             if dobj.get_start_date() != gen.lib.Date.EMPTY: | ||||
|                                 d = gen.lib.Date(dobj) | ||||
|                                 val = d.get_start_date() | ||||
|                                 val = d.get_year() - years | ||||
|                                 d.set_year(val) | ||||
|                                 return (d, d.copy_offset_ymd(self.MAX_AGE_PROB_ALIVE), | ||||
|                                         _("descendent birth-related date"), | ||||
|                                         child) | ||||
|  | ||||
|                         elif ev and ev.type.is_death_fallback(): | ||||
|                             dobj = ev.get_date_object()  | ||||
|                             if dobj.get_start_date() != gen.lib.Date.EMPTY: | ||||
|                                 return (dobj.copy_offset_ymd(- self.AVG_GENERATION_GAP),  | ||||
|                                         dobj.copy_offset_ymd(- self.AVG_GENERATION_GAP + self.MAX_AGE_PROB_ALIVE), | ||||
|                                         _("descendent death-related date"), | ||||
|                                         child) | ||||
|  | ||||
|             return (None, None, "", None) | ||||
|  | ||||
|         # If there are descendants that are too old for the person to have | ||||
|         # been alive in the current year then they must be dead. | ||||
|  | ||||
|         date1, date2, explain, other = None, None, "", None | ||||
|         try: | ||||
|             date1, date2, explain, other = descendants_too_old(person, self.AVG_GENERATION_GAP) | ||||
|         except RuntimeError: | ||||
|             raise Errors.DatabaseError( | ||||
|                 _("Database error: %s is defined as his or her own ancestor") % | ||||
|                 name_displayer.display(person)) | ||||
|  | ||||
|         if date1 and date2: | ||||
|             return (date1, date2, explain, other) | ||||
|  | ||||
|         def ancestors_too_old(person, year): | ||||
|             family_handle = person.get_main_parents_family_handle() | ||||
|             if family_handle:                 | ||||
|                 family = self.db.get_family_from_handle(family_handle) | ||||
|                 father_handle = family.get_father_handle() | ||||
|                 if father_handle: | ||||
|                     father = self.db.get_person_from_handle(father_handle) | ||||
|                     father_birth_ref = father.get_birth_ref() | ||||
|                     if father_birth_ref and father_birth_ref.get_role().is_primary(): | ||||
|                         father_birth = self.db.get_event_from_handle( | ||||
|                             father_birth_ref.ref) | ||||
|                         dobj = father_birth.get_date_object() | ||||
|                         if dobj.get_start_date() != gen.lib.Date.EMPTY: | ||||
|                             return (dobj.copy_offset_ymd(- year),  | ||||
|                                     dobj.copy_offset_ymd(- year + self.MAX_AGE_PROB_ALIVE), | ||||
|                                     _("ancestor birth date"), | ||||
|                                     father) | ||||
|                     father_death_ref = father.get_death_ref() | ||||
|                     if father_death_ref and father_death_ref.get_role().is_primary(): | ||||
|                         father_death = self.db.get_event_from_handle( | ||||
|                             father_death_ref.ref) | ||||
|                         dobj = father_death.get_date_object() | ||||
|                         if dobj.get_start_date() != gen.lib.Date.EMPTY: | ||||
|                             return (dobj.copy_offset_ymd(- year - self.MAX_AGE_PROB_ALIVE),  | ||||
|                                     dobj.copy_offset_ymd(- year - self.MAX_AGE_PROB_ALIVE + self.MAX_AGE_PROB_ALIVE), | ||||
|                                     _("ancestor death date"), | ||||
|                                     father) | ||||
|  | ||||
|                     # Check fallback data: | ||||
|                     for ev_ref in father.get_primary_event_ref_list(): | ||||
|                         ev = self.db.get_event_from_handle(ev_ref.ref) | ||||
|                         if ev and ev.type.is_birth_fallback(): | ||||
|                             dobj = ev.get_date_object()  | ||||
|                             if dobj.get_start_date() != gen.lib.Date.EMPTY: | ||||
|                                 return (dobj.copy_offset_ymd(- year),  | ||||
|                                         dobj.copy_offset_ymd(- year + self.MAX_AGE_PROB_ALIVE), | ||||
|                                         _("ancestor birth-related date"), | ||||
|                                         father) | ||||
|  | ||||
|                         elif ev and ev.type.is_death_fallback(): | ||||
|                             dobj = ev.get_date_object()  | ||||
|                             if dobj.get_start_date() != gen.lib.Date.EMPTY: | ||||
|                                 return (dobj.copy_offset_ymd(- year - self.MAX_AGE_PROB_ALIVE),  | ||||
|                                         dobj.copy_offset_ymd(- year - self.MAX_AGE_PROB_ALIVE + self.MAX_AGE_PROB_ALIVE), | ||||
|                                         _("ancestor death-related date"), | ||||
|                                         father) | ||||
|  | ||||
|                     date1, date2, explain, other = ancestors_too_old (father, year - self.AVG_GENERATION_GAP) | ||||
|                     if date1 and date2: | ||||
|                         return date1, date2, explain, other | ||||
|  | ||||
|                 mother_handle = family.get_mother_handle() | ||||
|                 if mother_handle: | ||||
|                     mother = self.db.get_person_from_handle(mother_handle) | ||||
|                     mother_birth_ref = mother.get_birth_ref() | ||||
|                     if mother_birth_ref and mother_birth_ref.get_role().is_primary(): | ||||
|                         mother_birth = self.db.get_event_from_handle(mother_birth_ref.ref) | ||||
|                         dobj = mother_birth.get_date_object() | ||||
|                         if dobj.get_start_date() != gen.lib.Date.EMPTY: | ||||
|                             return (dobj.copy_offset_ymd(- year),  | ||||
|                                     dobj.copy_offset_ymd(- year + self.MAX_AGE_PROB_ALIVE), | ||||
|                                     _("ancestor birth date"), | ||||
|                                     mother) | ||||
|                     mother_death_ref = mother.get_death_ref() | ||||
|                     if mother_death_ref and mother_death_ref.get_role().is_primary(): | ||||
|                         mother_death = self.db.get_event_from_handle( | ||||
|                             mother_death_ref.ref) | ||||
|                         dobj = mother_death.get_date_object() | ||||
|                         if dobj.get_start_date() != gen.lib.Date.EMPTY: | ||||
|                             return (dobj.copy_offset_ymd(- year - self.MAX_AGE_PROB_ALIVE),  | ||||
|                                     dobj.copy_offset_ymd(- year - self.MAX_AGE_PROB_ALIVE + self.MAX_AGE_PROB_ALIVE), | ||||
|                                     _("ancestor death date"), | ||||
|                                     mother) | ||||
|  | ||||
|                     # Check fallback data: | ||||
|                     for ev_ref in mother.get_primary_event_ref_list(): | ||||
|                         ev = self.db.get_event_from_handle(ev_ref.ref) | ||||
|                         if ev and ev.type.is_birth_fallback(): | ||||
|                             dobj = ev.get_date_object()  | ||||
|                             if dobj.get_start_date() != gen.lib.Date.EMPTY: | ||||
|                                 return (dobj.copy_offset_ymd(- year),  | ||||
|                                         dobj.copy_offset_ymd(- year + self.MAX_AGE_PROB_ALIVE), | ||||
|                                         _("ancestor birth-related date"), | ||||
|                                         mother) | ||||
|  | ||||
|                         elif ev and ev.type.is_death_fallback(): | ||||
|                             dobj = ev.get_date_object()  | ||||
|                             if dobj.get_start_date() != gen.lib.Date.EMPTY: | ||||
|                                 return (dobj.copy_offset_ymd(- year - self.MAX_AGE_PROB_ALIVE),  | ||||
|                                         dobj.copy_offset_ymd(- year - self.MAX_AGE_PROB_ALIVE + self.MAX_AGE_PROB_ALIVE), | ||||
|                                         _("ancestor death-related date"), | ||||
|                                         mother) | ||||
|  | ||||
|                     date1, date2, explain, other = ancestors_too_old (mother, year - self.AVG_GENERATION_GAP) | ||||
|                     if date1 and date2: | ||||
|                         return (date1, date2, explain, other) | ||||
|  | ||||
|             return (None, None, "", None) | ||||
|  | ||||
|         # If there are ancestors that would be too old in the current year | ||||
|         # then assume our person must be dead too. | ||||
|         date1, date2, explain, other = ancestors_too_old (person, - self.AVG_GENERATION_GAP) | ||||
|         if date1 and date2: | ||||
|             return (date1, date2, explain, other) | ||||
|  | ||||
|         # If we can't find any reason to believe that they are dead we | ||||
|         # must assume they are alive. | ||||
|  | ||||
|         return (None, None, "", None) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user