def birth_before_parents_death(individuals_dict, families_dict): result_error_messages = list() for family_id, family_info in families_dict.items(): husb_info = individuals_dict[family_info['HUSB']] wife_info = individuals_dict[family_info['WIFE']] if husb_info.get('DEAT') != None and husb_info.get('DEAT') != 'NA': if family_info.get('CHIL') != None and family_info.get('CHIL') != 'NA': for child in family_info.get('CHIL'): child_info = individuals_dict[child] if husb_info.get('DEAT') == "NA" or type(husb_info.get('DEAT').date_time_obj) is str or child_info.get('BIRT') == "NA" or type(child_info.get('BIRT')) is str: pass else: try: if Date.get_dates_difference(child_info.get('BIRT').date_time_obj, husb_info.get('DEAT').date_time_obj) < 0: raise ValueError(f"ERROR: US09: {family_id}: Husband died before the birth of his child") except ValueError as e: result_error_messages.append(f"ERROR: US09: {family_id}: Husband died before the birth of his child") print(e) if wife_info.get('DEAT') != None and wife_info.get('DEAT') != 'NA': if family_info.get('CHIL') != None and family_info.get('CHIL') != 'NA': for child in family_info.get('CHIL'): child_info = individuals_dict[child] if wife_info.get('DEAT') == "NA" or type(wife_info.get('DEAT').date_time_obj) is str or child_info.get('BIRT') == "NA" or type(child_info.get('BIRT')) is str: pass else: try: if Date.get_dates_difference(child_info.get('BIRT').date_time_obj, wife_info.get('DEAT').date_time_obj) < 0: raise ValueError(f"ERROR: US09: {family_id} Wife died before the birth of her child") except ValueError as e: result_error_messages.append(f"ERROR: US09: {family_id} Wife died before the birth of her child") print(e) return result_error_messages
def check_birth_before_marriage_of_parents(family_info_dict, individual_info_dict): for family_id, family_info in family_info_dict.items(): # gets marriage and divorce dates in family if they exist if family_info.get("MARR") not in [None, 'NA']: marriage_date = Date(str(family_info.get("MARR"))) else: marriage_date = None if family_info.get("DIV") not in [None, 'NA']: divorce_date = Date(str(family_info.get("DIV"))) else: divorce_date = None # obtains all childen in family children = family_info.get('CHIL') #if children exist, it gets the birth dates and compares it to the marriage/divorce dates, and prints error if marriage is before birth and/or birth is after divorce if children not in [None, 'NA']: for child in children: child_dict = individual_info_dict.get(child) birth_date = Date(str(child_dict.get('BIRT'))) if type(marriage_date) is not str and marriage_date != None and type(marriage_date.date_time_obj) is not str and type(birth_date.date_time_obj) is not str: if marriage_date not in [None, 'NA'] and marriage_date.date_time_obj < birth_date.date_time_obj: print('ANOMOLY: FAMILY: US08: {}: Child {} born {} before marriage on {}'.format(family_id, child, birth_date, marriage_date)) if type(divorce_date) is not str and divorce_date != None and type(divorce_date.date_time_obj) is not str and type(birth_date.date_time_obj) is not str: if divorce_date not in [None, 'NA'] and birth_date.date_time_obj > divorce_date.date_time_obj: print('ANOMOLY: FAMILY: US08: {}: Child {} born {} after divorce on {}'.format(family_id, child, birth_date, divorce_date))
def check_150_years_age(individual_info_dict): age_limit = 150 # gets dates from individual info for individual_id, individual_info in individual_info_dict.items(): id = individual_id birth_date = Date(str(individual_info.get("BIRT"))) if individual_info.get("DEAT") not in [None, 'NA']: death_date = Date(str(individual_info.get("DEAT"))) else: death_date = None # calculates age with the dates if death_date == None and birth_date != None: age = Date.get_dates_difference(birth_date.date_time_obj) else: if death_date != None and birth_date != None: age = Date.get_dates_difference(birth_date.date_time_obj, death_date.date_time_obj) # checks to see if age exceeds age limit and prints error if type(age) is not str and age > age_limit and death_date == None: print( 'ERROR: INDIVIDUAL: US07: {}: More than 150 years old - Birth date {}' .format(id, birth_date)) elif type(age) is not str and age > age_limit and death_date != None: print( 'ERROR: INDIVIDUAL: US07: {}: More than 150 years old at death - Birth date {}: Death date {}' .format(id, birth_date, death_date))
def test_us04(self): """ Test for US04 """ # Test with GEDCOM individual @I4@ husb_id = '@I4@' wife_id = '@I6@' marriage_dt = Date('18 Jun 2019') divorce_dt = Date('18 Jun 2018') fam_id = '@F3@' error_chk = True self.assertEqual( us04(husb_id, wife_id, marriage_dt, divorce_dt, fam_id, True), error_chk) return None
def us28(children, num_chil, fam_id, individuals, test=False): """ List siblings in families by decreasing age, i.e. oldest siblings first. """ # Needs Revision: import from gedcom_file_parser and use print_individuals_pretty_table function? birth_order = defaultdict(list) for i in range(num_chil): bd_key = individuals[children[i]]['BIRT'].date_time_obj if Date.is_valid_date(bd_key): if bd_key not in birth_order: birth_order[bd_key] = [children[i]] else: birth_order[bd_key].append(children[i]) print(f"US28: List: Eldest to youngest children in family '{fam_id}'.") pt = PrettyTable(field_names=["ID", "Name", "Date of Birth"]) for birthdate, child_list in sorted(birth_order.items(), reverse=False): child_list_len = len(child_list) if child_list_len == 1: child_info = [ child_list[0], individuals[child_list[0]]['NAME'], birthdate.strftime('%d %b %Y') ] pt.add_row(child_info) elif child_list_len > 1: for i in range(child_list_len): child_info = [ child_list[i], individuals[child_list[i]]['NAME'], birthdate.strftime('%d %b %Y') ] pt.add_row(child_info) if test: return str(pt) else: print(pt)
def test_us05(self): """ Test for US05 """ # Test with GEDCOM individual @I6@ husb_id = '@I4@' wife_id = '@I6@' husb_death_dt = Date('18 Jun 2020') wife_death_dt = Date('18 Jun 2017') marriage_dt = Date('18 Jun 2019') fam_id = '@F3@' error_chk = [False, True] self.assertEqual( us05(husb_id, husb_death_dt, wife_id, wife_death_dt, marriage_dt, fam_id, True), error_chk) return None
def print_individuals_pretty_table(individuals_dict, test=False): pt = PrettyTable(field_names=[ "ID", "Name", "Gender", "Birthday", "Age", "Alive", "Death", "Child", "Spouse"]) for individual_id, individual_info in individuals_dict.items(): individual_info["ALIVE"] = individual_info.get("DEAT") == None if individual_info.get("BIRT") != None: birth_date = individual_info.get("BIRT").date_time_obj death_date = None if individual_info.get("DEAT") != None: death_date = individual_info.get("DEAT").date_time_obj individual_info["AGE"] = Date.get_dates_difference(birth_date, death_date) individual_info["FAMC"] = individual_info.get( "FAMC") if individual_info.get("FAMC") != None else "NA" individual_info["FAMS"] = individual_info.get( "FAMS") if individual_info.get("FAMS") != None else "NA" individual_info["DEAT"] = individual_info.get( "DEAT") if individual_info.get("DEAT") != None else "NA" individual_info_list = [individual_id] for key in get_individual_pretty_Table_order(): individual_info_list.append(individual_info.get(key)) pt.add_row(individual_info_list) if test: return individuals_dict else: print(pt)
def list_upcoming_birthdays(individual_info_dict, use_todays_date=True): """ Lists all birthdays within a month in a GEDCOM file. """ upcoming_birthday_list = [] if use_todays_date == True: today = datetime.date.today() else: today = datetime.date(2019, 6, 1) for individual_id, individual_info in individual_info_dict.items(): id = individual_id name = individual_info.get('NAME') birth_date = Date(str(individual_info.get("BIRT"))).date_time_obj if birth_date not in [None, 'NA', '']: this_year_birthday = datetime.date(today.year, birth_date.month, birth_date.day) difference = this_year_birthday - today if difference > datetime.timedelta(0) and difference < datetime.timedelta(30): info = [id, name] upcoming_birthday_list.append(info) pt = '' if len(upcoming_birthday_list) > 0: pt = PrettyTable(field_names=["ID", "Name"]) for id, name in upcoming_birthday_list: mults_info_list = [id, name] pt.add_row(mults_info_list) if pt != '': return_print = "US38: List: The following individuals have upcoming birthdays within 30 days!\n" + str(pt) else: return_print = None return return_print
def us01(individuals, families): """ Check US01 Dates (birth, marriage, divorce, death) should not be after the current date.""" errors = dict() i = 0 for ind_id, ind in individuals.items( ): # each ind is dict with the attributes of the individual error1, error2, error3, error4 = False, False, False, False if type(ind['BIRT'].date_time_obj) is not str: if ind['BIRT'] != 'NA': if Date.get_dates_difference(ind['BIRT'].date_time_obj) < 0: print( f"US01: Error: Individual's '{ind_id}' birthday '{ind['BIRT'].date_time_obj.strftime('%d %b %Y')}' occurs in the future." ) error1 = True if ind['DEAT'] != 'NA' and type(ind['DEAT'].date_time_obj) is not str: if Date.get_dates_difference(ind['DEAT'].date_time_obj) < 0: print( f"US01: Error: Individual's '{ind_id}' death date '{ind['DEAT'].date_time_obj.strftime('%d %b %Y')}' occurs in the future." ) error2 = True if ind['FAMS'] != 'NA': if families[ind['FAMS']]['MARR'] != "NA" and type( families[ind['FAMS']]['MARR'].date_time_obj) is not str: if families[ind['FAMS']]['MARR'] != 'NA': if Date.get_dates_difference( families[ind['FAMS']]['MARR'].date_time_obj) < 0: print( f"US01: Error: Individual's '{ind_id}' marriage date '{families[ind['FAMS']]['MARR'].date_time_obj.strftime('%d %b %Y')}' occurs in the future." ) error3 = True if families[ind['FAMS']]['DIV'] != 'NA' and type( families[ind['FAMS']]['DIV'].date_time_obj) is not str: if Date.get_dates_difference( families[ind['FAMS']]['DIV'].date_time_obj) < 0: print( f"US01: Error: Individual's '{ind_id}' divorce date '{families[ind['FAMS']]['DIV'].date_time_obj.strftime('%d %b %Y')}' occurs in the future." ) error4 = True errors[i] = [error1, error2, error3, error4] i += 1 return errors
def test_us02_us10(self): """ Test for US02 and US10 """ # Test with GEDCOM individual @I4@ husb_id = '@I4@' wife_id = '@I6@' husb_birth_dt = Date('18 Jun 2021') wife_birth_dt = Date('18 Jun 2000') marriage_dt = Date('18 Jun 2019') fam_id = '@F3@' error_chk = [True, False, True, False] # Must add functionality of Date Class prior to sending dates to US02 self.assertEqual( us02(husb_id, husb_birth_dt, wife_id, wife_birth_dt, marriage_dt, fam_id, True), error_chk) return None
def us10(dt1, dt2): """ Check US10 Marriage should be at least 14 years after birth of both spouses (parents must be at least 14 years old) """ try: date_diff = Date.get_dates_difference(dt1.date_time_obj, dt2.date_time_obj) if type(date_diff) is str: raise ValueError if date_diff >= 14: return False if date_diff < 14: return True except: print("Data Error:", dt1, dt2)
def date_before(dt1, dt2): """ Send two dates to Date class for comparison """ try: date_diff = Date.get_dates_difference(dt1.date_time_obj, dt2.date_time_obj) if type(date_diff) is str: raise ValueError if date_diff >= 0: return False if date_diff <= -1: return True except: print('Data Error', dt1, dt2)
def check_bigamy(individual_info_dict, family_info_dict): for individual_id, individual_info in individual_info_dict.items(): id = individual_id name_place = individual_info.get('NAME') name = re.sub('/', '', name_place) marriage_count = 0 start_dates = [] end_dates = [] for family_id, family_info in family_info_dict.items(): wife_id = family_info.get('WIFE') husband_id = family_info.get('HUSB') if id == wife_id or id == husband_id: if id == wife_id: spouse_death = individual_info_dict[husband_id].get('DEAT') # print(family_info.get('MARR')) # print(spouse_death) elif id == husband_id: spouse_death = individual_info_dict[wife_id].get('DEAT') # print(family_info.get('MARR')) # print(spouse_death) Range = namedtuple('Range', ['start', 'end']) if family_info.get('DIV') not in [None, 'NA']: length_of_marriage = Range(start=family_info.get('MARR'), end=family_info.get('DIV')) elif spouse_death not in [None, 'NA']: length_of_marriage = Range(start=family_info.get('MARR'), end=spouse_death) else: length_of_marriage = Range(start=family_info.get('MARR'), end=Date(datetime.datetime.today().strftime('%d %b %Y'))) if family_info.get('MARR') not in [None, 'NA']: start_dates.append(length_of_marriage.start.date_time_obj) end_dates.append(length_of_marriage.end.date_time_obj) marriage_count += 1 more_than_one_marriage_at_given_time = False if marriage_count > 1: latest_start = max(start_dates) earliest_end = min(end_dates) if type(latest_start) is not str and latest_start != None: if type(earliest_end) is not str and earliest_end != None: delta = (earliest_end - latest_start).days overlap = max(0, delta) if overlap > 0: more_than_one_marriage_at_given_time = True if more_than_one_marriage_at_given_time == True: print('ANOMOLY: INDIVIDUAL: US11: {}: Bigamy detected: {} married to multiple spouses at the same time'.format(id, name))
def check_parents_not_too_old(individual_info_dict, family_info_dict): for family_id, family_info in family_info_dict.items(): wife_id = family_info.get('WIFE') husband_id = family_info.get('HUSB') children = family_info.get('CHIL') husb_dict = individual_info_dict.get(husband_id) wife_dict = individual_info_dict.get(wife_id) husb_birth_date = Date(str(husb_dict.get('BIRT'))) wife_birth_date = Date(str(wife_dict.get('BIRT'))) parents_too_old = False if children not in [None, 'NA']: for child in children: child_dict = individual_info_dict.get(child) birth_date = Date(str(child_dict.get('BIRT'))) too_old_age_difference = 65 if type(husb_birth_date) is not str and husb_birth_date != None and type(husb_birth_date.date_time_obj) is not str and type(husb_birth_date.date_time_obj) is not str: if type(wife_birth_date) is not str and wife_birth_date != None and type(wife_birth_date.date_time_obj) is not str and type(wife_birth_date.date_time_obj) is not str: if type(birth_date) is not str and birth_date != None and type(birth_date.date_time_obj) is not str and type(birth_date.date_time_obj) is not str: if Date.get_dates_difference(husb_birth_date.date_time_obj, birth_date.date_time_obj) > too_old_age_difference or Date.get_dates_difference(wife_birth_date.date_time_obj, birth_date.date_time_obj) > too_old_age_difference: parents_too_old = True if parents_too_old == True: print('ANOMOLY: FAMILY: US12: {}: Parents are too old: Parent(s) were greater than 65 years old when child was born'.format(family_id))
def us10(dt1, dt2, spouse, fam_id): """ Check US10 Marriage should be at least 14 years after birth of both spouses (parents must be at least 14 years old) """ try: date_diff = Date.get_dates_difference(dt1.date_time_obj, dt2.date_time_obj) if type(date_diff) is str: raise ValueError if date_diff >= 14: return False if date_diff < 14: return True except: print( f"Data Error: Birth date '{dt1}' and marriage date '{dt2}' for '{spouse}' in family '{fam_id}' are not in a compatible format." )
def us03(individuals, test=False): """ Check US03 Birth should occur before death of an individual.""" for ind_id, ind in individuals.items( ): # each ind is dict with the attributes of the individual if ind['BIRT'] != 'NA': birth_dt = ind['BIRT'].date_time_obj if ind['DEAT'] != 'NA': death_dt = ind['DEAT'].date_time_obj if Date.get_dates_difference(birth_dt, death_dt) < 0: print( f"US03: Error: Individual's '{ind_id}' birthday '{ind['BIRT'].date_time_obj.strftime('%d %b %Y')}' occurs after the death date '{ind['DEAT'].date_time_obj.strftime('%d %b %Y')}'." ) if test: return ind_id else: return None
def us35(individuals, test=False): """ List all people in a GEDCOM file who were born in the last 30 days. """ print( 'US35: List: The following people were born within the last 30 days') pt = PrettyTable(field_names=["ID", "Name", "Date of Birth"]) for ind_id, ind in individuals.items(): if Date.is_valid_date(ind['BIRT'].date_time_obj): diff, time_typ = get_dates_diff(ind['BIRT'].date_time_obj) if time_typ == 'days' and diff <= 30: recent_births = [ ind_id, ind['NAME'], (ind['BIRT'].date_time_obj).strftime('%d %b %Y') ] pt.add_row(recent_births) if test: return (str(pt)) else: print(pt) return None
def list_upcoming_anniversaries(individual_info_dict, family_info_dict, use_todays_date=True): """ Lists all anniversaries that occur within a month in a GEDCOM file. """ upcoming_anniversary_list = [] if use_todays_date == True: today = datetime.date.today() else: today = datetime.date(2019, 6, 1) pt = '' for family_id, family_info in family_info_dict.items(): wife_id = family_info.get('WIFE') husband_id = family_info.get('HUSB') wife_name = '' husb_name = '' for individual_id, individual_info in individual_info_dict.items(): if individual_id == wife_id: wife_name = individual_info.get('NAME') elif individual_id == husband_id: husb_name = individual_info.get('NAME') wedding_date = Date(str(family_info.get("MARR"))).date_time_obj if wedding_date not in [None, 'NA', '']: this_year_anniversary = datetime.date(today.year, wedding_date.month, wedding_date.day) difference = this_year_anniversary - today if difference > datetime.timedelta(0) and difference < datetime.timedelta(30): info = [wife_id, wife_name, husband_id, husb_name] upcoming_anniversary_list.append(info) pt = '' if len(upcoming_anniversary_list) > 0: pt = PrettyTable(field_names=["Wife ID", "Wife Name", "Husband ID", "Husband Name"]) for info in upcoming_anniversary_list: pt.add_row(info) if pt != '': return_print = "US39: List: The following couples have upcoming anniversaries within 30 days!\n" + str(pt) else: return_print = None return return_print
def us03(individuals): """ Check US03 Birth should occur before death of an individual.""" i = 0 errors = dict() for ind_id, ind in individuals.items( ): # each ind is dict with the attributes of the individual errors[i] = False if type(ind['BIRT'].date_time_obj) is not str and type( ind['DEAT']) is not str and type( ind['DEAT'].date_time_obj) is not str: if ind['BIRT'] != 'NA': birth_dt = ind['BIRT'].date_time_obj if ind['DEAT'] != 'NA': death_dt = ind['DEAT'].date_time_obj if Date.get_dates_difference(birth_dt, death_dt) < 0: print( f"US03: Error: Individual's '{ind_id}' birthday '{ind['BIRT'].date_time_obj.strftime('%d %b %Y')}' occurs after the death date '{ind['DEAT'].date_time_obj.strftime('%d %b %Y')}'." ) errors[i] = True i += 1 return errors
def us13(children, num_chil, fam_id, individuals, test=False): """ Birth dates of siblings should be more than 8 months apart or less than 2 days apart. """ if test: error1, error2 = False, False error3 = '' errors = list() bd_dict = defaultdict(list) for i in range(num_chil): bd_key = individuals[children[i]]['BIRT'].date_time_obj if Date.is_valid_date(bd_key): if bd_key not in bd_dict: bd_dict[bd_key] = [children[i]] else: bd_dict[bd_key].append(children[i]) test_next = True for bd_child, child in sorted(bd_dict.items(), reverse=True): error = False if len(bd_dict[bd_child]) == 1: if test_next: bd_sib1 = bd_child child1 = child test_next = False else: bd_sib2 = bd_child child2 = child diff, time_typ = get_dates_diff(bd_sib1, bd_sib2) if time_typ == 'years': continue elif time_typ == 'months' and diff < 8: print( f"US13: Error: Child '{child1}' and Child '{child2}' in family '{fam_id}' are born more than 2 days and less than 8 months apart." ) error1 = True elif time_typ == 'days' and diff > 2: print( f"US13: Error: Child '{child1}' and Child '{child2}' in family '{fam_id}' are born more than 2 days and less than 8 months apart." ) error1 = True test_next = True elif len(bd_dict[bd_child]) > 1: error2, error3 = us14(len(bd_dict[bd_child]), bd_child, bd_dict[bd_child], fam_id, individuals, test) test_next = True errors = [error1, error2, error3] return errors else: bd_dict = defaultdict(list) for i in range(num_chil): bd_key = individuals[children[i]]['BIRT'].date_time_obj if Date.is_valid_date(bd_key): if bd_key not in bd_dict: bd_dict[bd_key] = [children[i]] else: bd_dict[bd_key].append(children[i]) test_next = True for bd_child, child in sorted(bd_dict.items(), reverse=True): if len(bd_dict[bd_child]) == 1: if test_next: bd_sib1 = bd_child child1 = child test_next = False else: bd_sib2 = bd_child child2 = child diff, time_typ = get_dates_diff(bd_sib1, bd_sib2) if time_typ == 'years': continue elif time_typ == 'months' and diff < 8: print( f"US13: Error: Child '{child1}' and Child '{child2}' in family '{fam_id}' are born more than 2 days and less than 8 months apart." ) elif time_typ == 'days' and diff > 2: print( f"US13: Error: Child '{child1}' and Child '{child2}' in family '{fam_id}' are born more than 2 days and less than 8 months apart." ) test_next = True elif len(bd_dict[bd_child]) > 1: test_next = True
def us36(individuals, families, test=False): """ List all people in a GEDCOM file who died in the last 30 days. """ def us37(ind_id, individuals, families, test=False): """ List all living spouses and descendants of people in a GEDCOM file who died in the last 30 days. """ def get_descendants(ind_id, individuals, families, so_far=None): """ return a set of individual ids of all descendants of ind_id """ if so_far is None: descendants = set() else: descendants = so_far # the descendants we've already checked if individuals[ind_id]['FAMS'] != 'NA': # get the descendants for all of ind_id's children fam_id = individuals[ind_id]['FAMS'] if families[fam_id]['CHIL'] != 'NA': child_in_desc = False for child in families[fam_id]['CHIL']: if child not in descendants: descendants.add( child) # this child is a descendant descendants.update( get_descendants(child, individuals, families, descendants) ) # add all of the children of child to the set as well else: child_in_desc = True if child_in_desc == True: print( f"US37: WARNING: {ind_id} is a descendant of him/her self in {fam_id}" ) return descendants if individuals[ind_id]['FAMS'] != 'NA': pt = PrettyTable(field_names=["ID", "Name", "Relation"]) fam_id = individuals[ind_id]['FAMS'] if families[fam_id]['WIFE'] == ind_id: if families[fam_id]['HUSB'] != 'NA': relation = 'Husband' recent_survivor = [ families[fam_id]['HUSB'], families[fam_id]['HNAME'], relation ] pt.add_row(recent_survivor) elif families[fam_id]['HUSB'] == ind_id: if families[fam_id]['WIFE'] != 'NA': relation = 'Wife' recent_survivor = [ families[fam_id]['WIFE'], families[fam_id]['WNAME'], relation ] pt.add_row(recent_survivor) descendants = get_descendants(ind_id, individuals, families) if len(descendants) > 0: for child in descendants: recent_survivor = [ child, individuals[child]['NAME'], 'Descendant' ] pt.add_row(recent_survivor) if test: return str(pt) else: print( f"US37: List: The following people are living spouses and descendents of '{individuals[ind_id]['NAME']}' who died within the last 30 days" ) print(pt) return None # End US37 pt = PrettyTable(field_names=["ID", "Name", "Date of Death"]) for ind_id, ind in individuals.items(): if ind['DEAT'] != 'NA' and Date.is_valid_date( ind['DEAT'].date_time_obj): diff, time_typ = get_dates_diff(ind['DEAT'].date_time_obj) if time_typ == 'days' and diff <= 30: us37_test = us37(ind_id, individuals, families, test) recent_deaths = [ ind_id, ind['NAME'], (ind['DEAT'].date_time_obj).strftime('%d %b %Y') ] pt.add_row(recent_deaths) if test: return str(pt), us37_test else: print('US36: List: The following people died within the last 30 days') print(pt) return None
def us34(individuals, families, fam_id='', test=False): """ List all couples who were married when the older spouse was more than twice as old as the younger spouse. """ if test: errors = list() error1, error2 = False, False if families[fam_id]['HUSB'] != 'NA' and Date.is_valid_date( individuals[families[fam_id]['HUSB']]['BIRT'].date_time_obj): husb_id = families[fam_id]['HUSB'] husb_bd = individuals[husb_id]['BIRT'].date_time_obj if families[fam_id]['WIFE'] != 'NA' and Date.is_valid_date( individuals[families[fam_id]['WIFE']]['BIRT'].date_time_obj): wife_id = families[fam_id]['WIFE'] wife_bd = individuals[wife_id]['BIRT'].date_time_obj if families[fam_id]['MARR'] != 'NA' and Date.is_valid_date( families[fam_id]['MARR'].date_time_obj): marr_dt = families[fam_id]['MARR'].date_time_obj check = [husb_bd, wife_bd, marr_dt] if None not in check: if Date.get_dates_difference(husb_bd, marr_dt) > ( 2 * Date.get_dates_difference(wife_bd, marr_dt)): error1 = True elif Date.get_dates_difference(wife_bd, marr_dt) > ( 2 * Date.get_dates_difference(husb_bd, marr_dt)): error2 = True errors = [error1, error2] return errors else: husb_bd, wife_bd, marr_dt = None, None, None for fam_id, fam in families.items(): if fam['HUSB'] != 'NA' and Date.is_valid_date( individuals[fam['HUSB']]['BIRT'].date_time_obj): husb_id = fam['HUSB'] husb_bd = individuals[husb_id]['BIRT'].date_time_obj if fam['WIFE'] != 'NA' and Date.is_valid_date( individuals[fam['WIFE']]['BIRT'].date_time_obj): wife_id = fam['WIFE'] wife_bd = individuals[wife_id]['BIRT'].date_time_obj if fam['MARR'] != 'NA' and Date.is_valid_date( fam['MARR'].date_time_obj): marr_dt = fam['MARR'].date_time_obj check = [husb_bd, wife_bd, marr_dt] if None not in check: if Date.get_dates_difference(husb_bd, marr_dt) > ( 2 * Date.get_dates_difference(wife_bd, marr_dt)): print( f"US34: Husband '{husb_id}' was more than twice as old as wife '{wife_id}' in family '{fam_id}' on marriage date '{marr_dt}'." ) elif Date.get_dates_difference(wife_bd, marr_dt) > ( 2 * Date.get_dates_difference(husb_bd, marr_dt)): print( f"US34: Wife '{wife_id}' was more than twice as old as wife '{husb_id}' in family '{fam_id}' on marriage date '{marr_dt}'." ) return None
def gedcom_file_parser(path, return_duplicate_ids = False): """gedcom file parser opens and reads a gedcom file line-byline and stores the fields of individuals and families in separate dictionaries. The key of individuals dictionary is the individual id, for families dictionary it is family id. Arguments: path {string} -- this is the path of the gedcom file Returns: {tuple of dictionaries} -- the return value is a tuple of individuals and families dictionary """ try: fp = open(path, "r") except FileNotFoundError: print("Can't open", path) else: duplicate_ids = [] with fp: line = fp.readline() individuals_dict = dict() family_dict = dict() while line: if line != "": tag_array = LEVEL_TAGS.get(line[0]) line_split = line.split() if tag_array == None: line = fp.readline() continue elif line_split[0] == "0": if len(line_split) > 2 and line_split[2] == "INDI": individual_id = line_split[1] if individuals_dict.get(individual_id) != None: duplicate_ids.append(individual_id) line = fp.readline() continue individuals_dict[individual_id] = {} line = fp.readline().rstrip("\n") if line: line_split = line.split() while "INDI" not in line_split: if "FAM" in line_split or not line: break if line_split[1] in get_individual_info_tags(): if line_split[1] == "BIRT": line = fp.readline().rstrip("\n") if line != "": line_split = line.split() if line_split[1] == "DATE": individuals_dict[individual_id]["BIRT"] = Date(" ".join( line_split[2:])) elif line_split[1] == "DEAT": line = fp.readline().rstrip("\n") if line != "": line_split = line.split() if line_split[1] == "DATE": individuals_dict[individual_id]["DEAT"] = Date(" ".join( line_split[2:])) else: individuals_dict[individual_id][line_split[1]] = " ".join( line_split[2:]) line = fp.readline().rstrip("\n") line_split = line.split() else: line = fp.readline().rstrip("\n") line_split = line.split() continue if "FAM" in line_split and len(line_split) > 2: family_id = line_split[1] if family_dict.get(family_id) != None: duplicate_ids.append(family_id) line = fp.readline() continue family_dict[family_id] = {} line = fp.readline().rstrip("\n") line_split = line.split() while "FAM" not in line_split: if line: if line_split[1] in get_family_info_tags(): if line_split[1] == "MARR": line = fp.readline().rstrip("\n") if line: line_split = line.split() if line_split[1] == "DATE": family_dict[family_id]["MARR"] = Date(" ".join( line_split[2:])) elif line_split[1] == "DIV": line = fp.readline().rstrip("\n") if line: line_split = line.split() if line_split[1] == "DATE": family_dict[family_id]["DIV"] = Date(" ".join( line_split[2:])) elif line_split[1] == "CHIL": if family_dict[family_id].get("CHIL") == None: family_dict[family_id]["CHIL"] = [ line_split[2]] else: family_dict[family_id]["CHIL"].append( line_split[2]) else: family_dict[family_id][line_split[1]] = " ".join( line_split[2:]) line = fp.readline().rstrip("\n") line_split = line.split() else: line = fp.readline().rstrip("\n") line_split = line.split() continue else: break else: if "INDI" not in line_split: line = fp.readline().rstrip("\n") continue else: line = fp.readline().rstrip("\n") continue if return_duplicate_ids: return individuals_dict, family_dict, duplicate_ids else: return individuals_dict, family_dict