def get_families(self, individual, family_type=gedcom.tags.GEDCOM_TAG_FAMILY_SPOUSE): """Return family elements listed for an individual family_type can be `gedcom.tags.GEDCOM_TAG_FAMILY_SPOUSE` (families where the individual is a spouse) or `gedcom.tags.GEDCOM_TAG_FAMILY_CHILD` (families where the individual is a child). If a value is not provided, `gedcom.tags.GEDCOM_TAG_FAMILY_SPOUSE` is default value. :type individual: IndividualElement :type family_type: str :rtype: list of FamilyElement """ if not isinstance(individual, IndividualElement): raise NotAnActualIndividualError( "Operation only valid for elements with %s tag" % gedcom.tags.GEDCOM_TAG_INDIVIDUAL) families = [] element_dictionary = self.get_element_dictionary() for child_element in individual.get_child_elements(): is_family = ( child_element.get_tag() == family_type and child_element.get_value() in element_dictionary and element_dictionary[child_element.get_value()].is_family()) if is_family: families.append(element_dictionary[child_element.get_value()]) return families
def get_marriage_years(self, individual): """Returns a list of marriage years (as integers) for an individual :type individual: IndividualElement :rtype: list of int """ dates = [] if not isinstance(individual, IndividualElement): raise NotAnActualIndividualError( "Operation only valid for elements with %s tag" % gedcom.tags.GEDCOM_TAG_INDIVIDUAL) # Get and analyze families where individual is spouse. families = self.get_families(individual, gedcom.tags.GEDCOM_TAG_FAMILY_SPOUSE) for family in families: for child in family.get_child_elements(): if child.get_tag() == gedcom.tags.GEDCOM_TAG_MARRIAGE: for childOfChild in child.get_child_elements(): if childOfChild.get_tag( ) == gedcom.tags.GEDCOM_TAG_DATE: date = childOfChild.get_value().split()[-1] try: dates.append(int(date)) except ValueError: pass return dates
def get_marriages(self, individual): """Returns a list of marriages of an individual formatted as a tuple (`str` date, `str` place) :type individual: IndividualElement :rtype: tuple """ marriages = [] if not isinstance(individual, IndividualElement): raise NotAnActualIndividualError( "Operation only valid for elements with %s tag" % gedcom.tags.GEDCOM_TAG_INDIVIDUAL) # Get and analyze families where individual is spouse. families = self.get_families(individual, gedcom.tags.GEDCOM_TAG_FAMILY_SPOUSE) for family in families: for family_data in family.get_child_elements(): if family_data.get_tag() == gedcom.tags.GEDCOM_TAG_MARRIAGE: date = '' place = '' for marriage_data in family_data.get_child_elements(): if marriage_data.get_tag( ) == gedcom.tags.GEDCOM_TAG_DATE: date = marriage_data.get_value() if marriage_data.get_tag( ) == gedcom.tags.GEDCOM_TAG_PLACE: place = marriage_data.get_value() marriages.append((date, place)) return marriages
def get_marriages(self, individual): """Returns a list of marriages of an individual formatted as a tuple (`str` date, `str` place) :type individual: IndividualElement :rtype: tuple """ marriages = [] if not isinstance(individual, IndividualElement): raise NotAnActualIndividualError( "Operation only valid for elements with %s tag" % gedcom.tags.GEDCOM_TAG_INDIVIDUAL) # Get and analyze families where individual is spouse. families = self.get_families(individual, gedcom.tags.GEDCOM_TAG_FAMILY_SPOUSE) # TODO: Combine this code with the IndividualElement.get_fact_data method. for family in families: for family_data in family.get_child_elements(): if family_data.get_tag() == gedcom.tags.GEDCOM_TAG_MARRIAGE: spouses = self.get_family_members( family, FAMILY_MEMBERS_TYPE_PARENTS) spouse = [ spouse.get_pointer() for spouse in spouses if spouse.get_pointer() != individual.get_pointer() ] value = spouse[0] if spouse else '' date = '' place = '' sources = [] note = '' for marriage_data in family_data.get_child_elements(): if marriage_data.get_tag( ) == gedcom.tags.GEDCOM_TAG_DATE: date = marriage_data.get_value() if marriage_data.get_tag( ) == gedcom.tags.GEDCOM_TAG_PLACE: place = marriage_data.get_value() if marriage_data.get_tag( ) == gedcom.tags.GEDCOM_TAG_SOURCE: master_source = marriage_data.get_value() reference = marriage_data.get_descendant_value( [gedcom.tags.GEDCOM_TAG_REFERENCE]) page = marriage_data.get_descendant_value( [gedcom.tags.GEDCOM_TAG_PAGE]) data = marriage_data.get_descendant_value([ gedcom.tags.GEDCOM_TAG_DATA, gedcom.tags.GEDCOM_TAG_TEXT ]) sources.append({ 'master': master_source, 'reference': reference, 'page': page, 'data': data }) if marriage_data.get_tag( ) == gedcom.tags.GEDCOM_TAG_NOTE: note = marriage_data.get_multi_line_value() marriages.append((value, date, place, sources, note)) return marriages
def marriage_year_match(self, individual, year): """Checks if one of the marriage years of an individual matches the supplied year. Year is an integer. :type individual: IndividualElement :type year: int :rtype: bool """ if not isinstance(individual, IndividualElement): raise NotAnActualIndividualError( "Operation only valid for elements with %s tag" % gedcom.tags.GEDCOM_TAG_INDIVIDUAL) years = self.get_marriage_years(individual) return year in years
def marriage_range_match(self, individual, from_year, to_year): """Check if one of the marriage years of an individual is in a given range. Years are integers. :type individual: IndividualElement :type from_year: int :type to_year: int :rtype: bool """ if not isinstance(individual, IndividualElement): raise NotAnActualIndividualError( "Operation only valid for elements with %s tag" % gedcom.tags.GEDCOM_TAG_INDIVIDUAL) years = self.get_marriage_years(individual) for year in years: if from_year <= year <= to_year: return True return False
def get_parents(self, individual, parent_type="ALL"): """Return elements corresponding to parents of an individual Optional parent_type. Default "ALL" returns all parents. "NAT" can be used to specify only natural (genetic) parents. :type individual: IndividualElement :type parent_type: str :rtype: list of IndividualElement """ if not isinstance(individual, IndividualElement): raise NotAnActualIndividualError( "Operation only valid for elements with %s tag" % gedcom.tags.GEDCOM_TAG_INDIVIDUAL) parents = [] families = self.get_families(individual, gedcom.tags.GEDCOM_TAG_FAMILY_CHILD) for family in families: if parent_type == "NAT": for family_member in family.get_child_elements(): if family_member.get_tag() == gedcom.tags.GEDCOM_TAG_CHILD \ and family_member.get_value() == individual.get_pointer(): for child in family_member.get_child_elements(): if child.get_value() == "Natural": if child.get_tag( ) == gedcom.tags.GEDCOM_PROGRAM_DEFINED_TAG_MREL: parents += self.get_family_members( family, gedcom.tags.GEDCOM_TAG_WIFE) elif child.get_tag( ) == gedcom.tags.GEDCOM_PROGRAM_DEFINED_TAG_FREL: parents += self.get_family_members( family, gedcom.tags.GEDCOM_TAG_HUSBAND) else: parents += self.get_family_members(family, "PARENTS") return parents
def get_ancestors(self, individual, ancestor_type="ALL"): """Return elements corresponding to ancestors of an individual Optional `ancestor_type`. Default "ALL" returns all ancestors, "NAT" can be used to specify only natural (genetic) ancestors. :type individual: IndividualElement :type ancestor_type: str :rtype: list of Element """ if not isinstance(individual, IndividualElement): raise NotAnActualIndividualError( "Operation only valid for elements with %s tag" % gedcom.tags.GEDCOM_TAG_INDIVIDUAL) parents = self.get_parents(individual, ancestor_type) ancestors = [] ancestors.extend(parents) for parent in parents: ancestors.extend(self.get_ancestors(parent)) return ancestors
def find_path_to_ancestor(self, descendant, ancestor, path=None): """Return path from descendant to ancestor :rtype: object """ if not isinstance(descendant, IndividualElement) and isinstance( ancestor, IndividualElement): raise NotAnActualIndividualError( "Operation only valid for elements with %s tag." % gedcom.tags.GEDCOM_TAG_INDIVIDUAL) if not path: path = [descendant] if path[-1].get_pointer() == ancestor.get_pointer(): return path else: parents = self.get_parents(descendant, "NAT") for parent in parents: potential_path = self.find_path_to_ancestor( parent, ancestor, path + [parent]) if potential_path is not None: return potential_path return None