def us06(self, file_path=None): """ return a list of objects whose divorce date is after death date """ file_path = file_path if file_path else get_data_file_path('us06.ged') family_tree = TreeLine().process_data(file_path) fam_list = family_tree.get_fam_list() indi_list_us06_fail = [] for fam in fam_list: husband_death_date = family_tree.get(fam.husb).get_death_date() if family_tree.get(fam.husb) else None wife_death_date = family_tree.get(fam.wife).get_death_date() if family_tree.get(fam.wife) else None divorce_date = fam.get_div_date() if divorce_date: if husband_death_date and wife_death_date: if divorce_date >= husband_death_date and divorce_date >= wife_death_date: warn_msg = f"death date {family_tree.get(fam.husb).get_death_date(TreeUtils.OUTPUT_DATE_FORMAT)}, {family_tree.get(fam.wife).get_death_date(TreeUtils.OUTPUT_DATE_FORMAT)} is before the divorce date for both {fam.get_div_date(TreeUtils.OUTPUT_DATE_FORMAT)}" fam.err = TreeError(TreeError.TYPE_ERROR, TreeError.ON_FAM, 'US06', fam.id, warn_msg) indi_list_us06_fail.append(fam) elif husband_death_date or wife_death_date: if husband_death_date and divorce_date >= husband_death_date: warn_msg = f"death date {family_tree.get(fam.husb).get_death_date(TreeUtils.OUTPUT_DATE_FORMAT)} of husband is before the divorce date {fam.get_div_date(TreeUtils.OUTPUT_DATE_FORMAT)}" fam.err = TreeError(TreeError.TYPE_ERROR, TreeError.ON_FAM, 'US06', fam.id, warn_msg) indi_list_us06_fail.append(fam) if wife_death_date and divorce_date >= wife_death_date: warn_msg = f"death date {family_tree.get(fam.wife).get_death_date(TreeUtils.OUTPUT_DATE_FORMAT)} of wife is before the divorce date {fam.get_div_date(TreeUtils.OUTPUT_DATE_FORMAT)}" fam.err = TreeError(TreeError.TYPE_ERROR, TreeError.ON_FAM, 'US06', fam.id, warn_msg) indi_list_us06_fail.append(fam) else: continue # if indi_list_us06_fail: # TreeUtils.print_report("US06 divorce date is after death date ", indi_list_us06_fail) return indi_list_us06_fail
def us08(self, file_path=None): """ returns a list of individuals whose birth date is before parent's marriage date or nine months after parent's divorce date """ # self.logger.error(TreeUtils.form_heading('Starting User Story 8', '#', 70)) file_path = file_path if file_path else get_data_file_path('us08.ged') family_tree = TreeLine().process_data(file_path) indi_list = family_tree.get_sorted_list(UserStoriesNy.INDI_TAG) indi_list_us08_fail = [] for indi in indi_list: birth_date = indi.get_birth_date() parent_marr_date = indi.get_parent_marr_date(family_tree) parent_div_date = indi.get_parent_div_date(family_tree) # if birth date is on or before marriage date, add indi to failure list # if birth_date and parent_marr_date and birth_date <= parent_marr_date: if date_greater_than(parent_marr_date, birth_date) or date_equal_to( parent_marr_date, birth_date): warn_msg = f'Birth date {birth_date.strftime(TreeUtils.OUTPUT_DATE_FORMAT)} ' \ f'is before or on parent\'s marriage date {parent_marr_date.strftime(TreeUtils.OUTPUT_DATE_FORMAT)}' indi.err = TreeError(TreeError.TYPE_ERROR, TreeError.ON_INDI, 'US08', indi.id, warn_msg) indi_list_us08_fail.append(indi) if date_greater_than(birth_date, add_to_date(parent_div_date, months=9)): warn_msg = f'Birth date {birth_date.strftime(TreeUtils.OUTPUT_DATE_FORMAT)} ' \ f'is more than 9 months after parent\'s divorce date {parent_div_date.strftime(TreeUtils.OUTPUT_DATE_FORMAT)}' indi.err = TreeError(TreeError.TYPE_ERROR, TreeError.ON_INDI, 'US08', indi.id, warn_msg) indi_list_us08_fail.append(indi) return indi_list_us08_fail
def us05(self, file_path=None): """ returns a list of objects whose marriage date is after death date""" family_tree = self.get_treedata(file_path) fam_list = family_tree.get_sorted_list(UserStoriesDg.FAM_TAG) fam_list_us05 = [] for fam in fam_list: marr_date = fam.get_marr_date() hus_death_date = fam.get_husb_death_date(family_tree) wife_death_date = fam.get_wife_death_date(family_tree) # if marr_date and hus_death_date and wife_death_date and wife_death_date <= marr_date and hus_death_date <= marr_date: if date_greater_than(marr_date, wife_death_date, True) and date_greater_than( marr_date, hus_death_date, True): warn_msg = f'Marriage {fam.get_marr_date(TreeUtils.OUTPUT_DATE_FORMAT)} should occur before death of {family_tree.get(fam.husb).name} - {family_tree.get(fam.husb).get_death_date(TreeUtils.OUTPUT_DATE_FORMAT)}, {family_tree.get(fam.wife).name} - {family_tree.get(fam.wife).get_death_date(TreeUtils.OUTPUT_DATE_FORMAT)}' fam.err = TreeError(TreeError.TYPE_ERROR, TreeError.ON_FAM, 'US05', fam.id, warn_msg) fam_list_us05.append(fam) # elif marr_date and hus_death_date and hus_death_date <= marr_date: elif date_greater_than(marr_date, hus_death_date, True): warn_msg = f'Marriage date {fam.get_marr_date(TreeUtils.OUTPUT_DATE_FORMAT)} should occur before death of {family_tree.get(fam.husb).name} - {family_tree.get(fam.husb).get_death_date(TreeUtils.OUTPUT_DATE_FORMAT)}' fam.err = TreeError(TreeError.TYPE_ERROR, TreeError.ON_FAM, 'US05', fam.id, warn_msg) fam_list_us05.append(fam) # elif marr_date and wife_death_date and wife_death_date <= marr_date: elif date_greater_than(marr_date, wife_death_date, True): warn_msg = f'Marriage date {fam.get_marr_date(TreeUtils.OUTPUT_DATE_FORMAT)} should occur before death of {family_tree.get(fam.wife).name} - {family_tree.get(fam.wife).get_death_date(TreeUtils.OUTPUT_DATE_FORMAT)}' fam.err = TreeError(TreeError.TYPE_ERROR, TreeError.ON_FAM, 'US05', fam.id, warn_msg) fam_list_us05.append(fam) return fam_list_us05
def us25(self, file_path=None): """ returns a children list with the same first name and birth date in a family """ family_tree = self.get_treedata(file_path) fam_list = family_tree.get_sorted_list(UserStoriesDg.FAM_TAG) fam_list_us25 = [] for fam in fam_list: fam_dict = {} for child in fam.chil: childname = family_tree.get(child).name child_birthdate = family_tree.get(child).get_birth_date() if childname and child_birthdate: childname = family_tree.get(child).name.replace( '/', '').split(' ')[0] if childname not in fam_dict: fam_dict[childname] = child_birthdate else: if child_birthdate == fam_dict[childname]: warn_msg = f'More than one child has the same first name - {childname} and birthdate - {family_tree.get(child).get_birth_date(TreeUtils.OUTPUT_DATE_FORMAT)}' fam.err = TreeError(TreeError.TYPE_ERROR, TreeError.ON_FAM, 'US25', fam.id, warn_msg) fam_list_us25.append(fam) continue else: fam_dict[childname] = child_birthdate return fam_list_us25
def check_indi_roles(self, fam, family_tree, failures): logger = self.logger husb_id = fam.husb wife_id = fam.wife chil_id_list = fam.get_children() logger.debug( f'checking indi records for [fam: {fam.id}, husb: {husb_id}, wife: {wife_id}, chil: {chil_id_list}]' ) all_indi_ids = get_id_list(family_tree.get_indi_list()) if husb_id: if husb_id in all_indi_ids: husb = family_tree.get(husb_id) logger.debug( f'{fam.id} husband definition found in record: {husb.id} = {husb.name}' ) else: warn_msg = f'{fam.id} husband {husb_id} definition NOT found in record' logger.debug(warn_msg) fam.err = TreeError(TreeError.TYPE_ANOMALY, TreeError.ON_FAM, 'US26', fam.id, warn_msg) failures.append(fam) if wife_id: if wife_id in all_indi_ids: wife = family_tree.get(wife_id) logger.debug( f'{fam.id} wife definition found in record: {wife.id} = {wife.name}' ) else: warn_msg = f'{fam.id} wife {wife_id} definition NOT found in record' logger.debug(warn_msg) fam.err = TreeError(TreeError.TYPE_ANOMALY, TreeError.ON_FAM, 'US26', fam.id, warn_msg) failures.append(fam) if chil_id_list: for child_id in chil_id_list: if child_id in all_indi_ids: child = family_tree.get(child_id) logger.debug( f'{fam.id} child definition found in record: {child.id} = {child.name}' ) else: warn_msg = f'{fam.id} child {child_id} definition NOT found in record' logger.debug(warn_msg) fam.err = TreeError(TreeError.TYPE_ANOMALY, TreeError.ON_FAM, 'US26', fam.id, warn_msg) failures.append(fam)
def check_family_roles(self, indi, family_tree, failures): logger = self.logger logger.debug( f'checking family records for [person: {indi.id} [{indi.name}], famc: {indi.famc}, fams: {indi.fams}]' ) # use getparent and getspouse methods without passing the familytree object, so that it returns the id # strings even if they are invalid i.e. not found in the family tree map parent_fam_id = indi.get_parent_family() spouse_fam_id_list = indi.get_spouse_families() children = indi.get_children(family_tree) all_fams_ids = get_id_list(family_tree.get_fam_list()) if parent_fam_id: if parent_fam_id in all_fams_ids: parent_fam = family_tree.get(parent_fam_id) logger.debug( f'{indi.id} parent family definition found in record: {parent_fam.id} = {parent_fam.husb} : {parent_fam.wife}' ) else: warn_msg = f'{indi.name} [{indi.id}] parent family [{indi.famc}] definition NOT found in record' logger.debug(warn_msg) indi.err = TreeError(TreeError.TYPE_ANOMALY, TreeError.ON_INDI, 'US26', indi.id, warn_msg) failures.append(indi) else: logger.debug( f'{indi.id} parent family id not supplied in indi definition') if spouse_fam_id_list: for spouse_fam_id in spouse_fam_id_list: if spouse_fam_id in all_fams_ids: spouse_fam = family_tree.get(spouse_fam_id) logger.debug( f'{indi.id} spouse family definition found in record: {spouse_fam.id} = {spouse_fam.husb} : {spouse_fam.wife}' ) else: warn_msg = f'{indi.name} [{indi.id}] spouse family [{indi.fams}] definition NOT found in record' logger.debug(warn_msg) indi.err = TreeError(TreeError.TYPE_ANOMALY, TreeError.ON_INDI, 'US26', indi.id, warn_msg) failures.append(indi) else: logger.debug( f'{indi.id} spouse family id not supplied in indi definition')
def us22(self, file_path=None): """ All individual IDs should be unique and all family IDs should be unique """ file_path = file_path if file_path else get_data_file_path('us22.ged') # file_path = get_data_file_path('us22.ged') family_tree = Tree(file_path) us22_fail = family_tree.duplicate_items for item in us22_fail: warn_msg = f'duplicate item [{item.id}], {item}' err_on = TreeError.ON_INDI if item.tag_name == TreeUtils.INDI else TreeError.ON_FAM item.err = TreeError(TreeError.TYPE_ERROR, err_on, 'US22', item.id, warn_msg) return us22_fail
def us15(self, file_path=None): """ returns a list of objects if family has more than 15 siblings """ fam_list = self.get_treedata(file_path).get_sorted_list( UserStoriesDg.FAM_TAG) fam_list_us15 = [] for fam in fam_list: if len(fam.chil) >= 15: warn_msg = f'Family has more than 15 siblings' fam.err = TreeError(TreeError.TYPE_ERROR, TreeError.ON_FAM, 'US15', fam.id, warn_msg) fam_list_us15.append(fam) return fam_list_us15
def us07(self, file_path=None): """returns a list of objects with age greater than or equal to 150""" # file_path = file_path if file_path else UserStoriesDg.FILE_PATH1 # processed_tree = TreeLine().process_data(file_path) indi_list = self.get_treedata(file_path).get_sorted_list( UserStoriesDg.INDI_TAG) indi_list_us07 = [] for indi in indi_list: if indi.get_age() >= 150: warn_msg = f'Age is greater than or equal to 150, {indi.name} Age: {indi.get_age()}' indi.err = TreeError(TreeError.TYPE_ERROR, TreeError.ON_INDI, 'US07', indi.id, warn_msg) indi_list_us07.append(indi) return indi_list_us07
def us01(self, file_path=None): """ returns a list of objects containing dates after current date """ # self.logger.error(TreeUtils.form_heading("Starting User Story 1", "#", 70)) file_path = file_path if file_path else get_data_file_path('us01.ged') family_tree = TreeLine().process_data(file_path) indi_list, fam_list = family_tree.get_sorted_list(UserStoriesNy.INDI_TAG), \ family_tree.get_sorted_list(UserStoriesNy.FAM_TAG) today_date = datetime.today() indi_list_us01, fam_list_us01 = [], [] # if there is error in both birth and death criteria, only birth will be listed for indi in indi_list: if date_greater_than(indi.get_birth_date(), today_date): warn_msg = f'Birthday {indi.get_birth_date(TreeUtils.OUTPUT_DATE_FORMAT)} occurs in future' indi.err = TreeError(TreeError.TYPE_ERROR, TreeError.ON_INDI, 'US01', indi.id, warn_msg) indi_list_us01.append(indi) if date_greater_than(indi.get_death_date(), today_date): warn_msg = f'Death day {indi.get_death_date(TreeUtils.OUTPUT_DATE_FORMAT)} occurs in future' indi.err = TreeError(TreeError.TYPE_ERROR, TreeError.ON_INDI, 'US01', indi.id, warn_msg) indi_list_us01.append(indi) # if there is error in both marriage and divorce criteria, only marriage will be listed for fam in fam_list: if date_greater_than(fam.get_marr_date(), today_date): warn_msg = f'Marriage date {fam.get_marr_date(TreeUtils.OUTPUT_DATE_FORMAT)} occurs in future' fam.err = TreeError(TreeError.TYPE_ERROR, TreeError.ON_FAM, 'US01', fam.id, warn_msg) fam_list_us01.append(fam) if date_greater_than(fam.get_div_date(), today_date): warn_msg = f'Divorce date {fam.get_div_date(TreeUtils.OUTPUT_DATE_FORMAT)} occurs in future' fam.err = TreeError(TreeError.TYPE_ERROR, TreeError.ON_FAM, 'US01', fam.id, warn_msg) fam_list_us01.append(fam) return indi_list_us01 + fam_list_us01
def us11(self, file_path=None): """ returns list of individuals whose marriage occured with two spouses at the same time """ family_tree = TreeLine().process_data(file_path) fam_list = family_tree.get_fam_list() indi_list_us11_fail = [] indi_list = family_tree.get_sorted_list(UserStoriesAm.INDI_TAG) for indi in indi_list: if len(indi.fams) > 1: indi_marr_dict = defaultdict(int) for spouse in indi.fams: marriage_date = family_tree.get(spouse).get_marr_date() if marriage_date: indi_marr_dict[marriage_date]+=1 for key, val in indi_marr_dict.items(): if val > 1: warn_msg = f"{indi.name} should not marry more than one person at same time" indi.err = TreeError(TreeError.TYPE_ERROR, TreeError.ON_INDI, 'US11', indi.id, warn_msg) indi_list_us11_fail.append(indi) return indi_list_us11_fail
def us16(self, file_path=None): """ returns list of males whose last name do not match their family name """ #file_path = file_path if file_path else get_data_file_path('us02.ged') family_tree = TreeLine().process_data(file_path) fam_list = family_tree.get_fam_list() indi_list_us16_fail = [] indi_list = family_tree.get_sorted_list(UserStoriesAm.INDI_TAG) for fam in fam_list: parent_full_name = (family_tree.get(fam.husb).name).split("/") parent_last_name = parent_full_name[1] for child in fam.chil: child_full_name = (family_tree.get(child).name).split("/") child_last_name = child_full_name[1] if parent_last_name != child_last_name: warn_msg = f"Last name of {family_tree.get(child).name} doesnot match with last name of family {family_tree.get(fam.husb).name}" fam.err = TreeError(TreeError.TYPE_ERROR, TreeError.ON_FAM, 'US16', fam.id, warn_msg) indi_list_us16_fail.append(fam) else: continue return indi_list_us16_fail
def us02(self, file_path=None): """return a list of objects whose birth date is after or on their marriage date """ file_path = file_path if file_path else get_data_file_path('us02.ged') family_tree = TreeLine().process_data(file_path) indi_list = family_tree.get_sorted_list(UserStoriesAm.INDI_TAG) indi_list_us02_fail = [] for indi in indi_list: birth_date = indi.get_birth_date() for spouse in indi.fams: marriage_date = family_tree.get(spouse).get_marr_date() if family_tree.get(spouse) else None if marriage_date and birth_date >= marriage_date: warn_msg = f"birth date {indi.get_birth_date(TreeUtils.OUTPUT_DATE_FORMAT)} should not occur after or on marriage date {family_tree.get(spouse).get_marr_date(TreeUtils.OUTPUT_DATE_FORMAT)}" indi.err = TreeError(TreeError.TYPE_ERROR, TreeError.ON_INDI, 'US02', indi.id, warn_msg) indi_list_us02_fail.append(indi) continue # if indi_list_us02_fail: # TreeUtils.print_report("US02 birth date is after marriage date ", indi_list_us02_fail) # print('prining indi us02 failed:') # for indi in indi_list_us02_fail: # print(indi) return indi_list_us02_fail
def us23(self, file_path=None): """ returns a list of individuals with the same name and birth date """ ind_list = self.get_treedata(file_path).get_sorted_list( UserStoriesDg.INDI_TAG) ind_list_us23 = [] ind_dict = {} for ind in ind_list: if ind.name and ind.get_birth_date(): ind.name = ind.name.replace('/', '') if ind.name not in ind_dict: ind_dict[ind.name] = ind.get_birth_date() else: if ind.get_birth_date() == ind_dict[ind.name]: warn_msg = f'More than one individual has same name - {ind.name} and birthdate - {ind.get_birth_date(TreeUtils.OUTPUT_DATE_FORMAT)}' ind.err = TreeError(TreeError.TYPE_ERROR, TreeError.ON_INDI, 'US23', ind.id, warn_msg) ind_list_us23.append(ind) continue else: ind_dict[ind.name] = ind.get_birth_date() return ind_list_us23
def us12(self, file_path=None): """ returns a list of objects if Parents are too old """ family_tree = self.get_treedata(file_path) fam_list = family_tree.get_sorted_list(UserStoriesDg.FAM_TAG) fam_list_us12 = [] for fam in fam_list: father_age = family_tree.get(fam.husb).get_age() mother_age = family_tree.get(fam.wife).get_age() for child in fam.chil: child_age = family_tree.get(child).get_age() father_child_diff = father_age - child_age if father_age and child_age else None mother_child_diff = mother_age - child_age if mother_age and child_age else None if father_child_diff and father_child_diff >= 80 or mother_child_diff and mother_child_diff >= 60: if father_child_diff and mother_child_diff and father_child_diff >= 80 and mother_child_diff >= 60: warn_msg = f'Father and Mother should be less than 80 years and 60 years older than their child - {family_tree.get(child).name}' elif father_child_diff and father_child_diff >= 80: warn_msg = f'Father should be less than 80 years than their child - {family_tree.get(child).name}' else: warn_msg = f'Mother should be less than 60 years than their child - {family_tree.get(child).name}' (family_tree.get(child)).err = TreeError( TreeError.TYPE_ERROR, TreeError.ON_INDI, 'US12', child, warn_msg) fam_list_us12.append(family_tree.get(child)) return fam_list_us12
def add_err(self, err_type, us_name, err_msg): self.err_list.append( TreeError(err_type, TreeError.ON_INDI, us_name, self.id, err_msg))