예제 #1
0
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
예제 #2
0
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)
예제 #8
0
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
예제 #9
0
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
예제 #11
0
 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)
예제 #12
0
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)
예제 #13
0
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))
예제 #14
0
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
예제 #17
0
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
예제 #18
0
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
예제 #19
0
파일: US03.py 프로젝트: sahlawat11/GEDCOM
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
예제 #21
0
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
예제 #22
0
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