示例#1
0
def create_family(ptr: str,
                  level: int = 0,
                  husb_ptrs: Tuple[str, ...] = None,
                  wife_ptrs: Tuple[str, ...] = None,
                  child_ptrs: Tuple[str, ...] = None,
                  marriage_place: str = None,
                  marriage_date: str = None,
                  divorce_place: str = None,
                  divorce_date: str = None):
    family_element = FamilyElement(level, ptr, tags.GEDCOM_TAG_FAMILY, '')
    if husb_ptrs:
        for husb_ptr in husb_ptrs:
            family_element.add_child_element(Element(level + 1, '', tags.GEDCOM_TAG_HUSBAND, husb_ptr))
    if wife_ptrs:
        for wife_ptr in wife_ptrs:
            family_element.add_child_element(Element(level + 1, '', tags.GEDCOM_TAG_WIFE, wife_ptr))
    if child_ptrs:
        for child_ptr in child_ptrs:
            family_element.add_child_element(Element(level + 1, '', tags.GEDCOM_TAG_CHILD, child_ptr))
    if marriage_date is not None or marriage_place is not None:
        family_element.add_child_element(
            create_event(tags.GEDCOM_TAG_MARRIAGE, marriage_place, marriage_date, level + 1))
    if divorce_place is not None or divorce_date is not None:
        family_element.add_child_element(create_event(tags.GEDCOM_TAG_DIVORCE, divorce_place, divorce_date, level + 1))
    return family_element
示例#2
0
 def export_sex(self, character: Character, element: Element):
     sex = character.get_property(PropertyTag.SEX).value
     if sex != Sex.UNDEFINED:
         element.new_child_element('SEX', '', {
             Sex.MALE: 'M',
             Sex.FEMALE: 'F'
         }[sex])
示例#3
0
    def test_gen_individual(self):
        birth_date = datetime.datetime(1980, 1, 1)
        death_date = datetime.datetime(2040, 1, 1)
        legal_name = LegalName(first_name="David", last_name="Schmidt")
        legal_name.save()
        birth_location = Location(city='New York', state='NY', country='US')
        birth_location.save()
        death_location = Location(city='Boston', state='MA', country='US')
        death_location.save()
        person = Person(
            legal_name=legal_name,
            gender="Male",
            birth_date=birth_date,
            birth_location=birth_location,
            death_date=death_date,
            death_location=death_location,
        )
        person.save()
        alternate_name = AlternateName(first_name='Lance',
                                       last_name='Springer',
                                       person=person)
        alternate_name.save()

        partner_partnership = Partnership()
        partner_partnership.save()

        person_partnership = PersonPartnership(person=person,
                                               partnership=partner_partnership)
        person_partnership.save()

        child_partnership = Partnership()
        child_partnership.save()
        child_partnership.children.add(person)

        ptr, individual = gedcom_generator.gen_individual(person)
        expected = gedcom_helpers.create_individual(
            f"@PERSON_{person.id}@",
            name="David Schmidt",
            sex='M',
            birth_place='New York, NY, US',
            birth_date=birth_date.strftime("%d %b %Y").upper(),
            death_place='Boston, MA, US',
            death_date=death_date.strftime("%d %b %Y").upper())
        expected.add_child_element(
            Element(1, '', tags.GEDCOM_TAG_NAME, 'Lance Springer'))
        expected.add_child_element(
            Element(1, '', tags.GEDCOM_TAG_GIVEN_NAME, 'David'))
        expected.add_child_element(
            Element(1, '', tags.GEDCOM_TAG_SURNAME, 'Schmidt'))
        expected.add_child_element(
            Element(1, '', tags.GEDCOM_TAG_FAMILY_SPOUSE,
                    f'@PARTNERSHIP_{partner_partnership.id}@'))
        expected.add_child_element(
            Element(1, '', tags.GEDCOM_TAG_FAMILY_CHILD,
                    f'@PARTNERSHIP_{child_partnership.id}@'))

        self.assertTrue(gedcom_helpers.element_equals(individual, expected))
示例#4
0
 def create_character_element(self, character: Character):
     element = Element(0, '@{}@'.format(character.id), 'INDI', '')
     element.new_child_element('NAME', '', str(character.label))
     for property_tag in self.properties:
         try:
             export_gedcom_property_methods[property_tag](self, character,
                                                          element)
         except (ExportPropertyException, EntityException):
             self.logger.error('{}: {} is impossible to export'.format(
                 self.__class__.__name__, property_tag))
     self.create_family(character)
     self.elements[character.id] = element
示例#5
0
 def _get_date_value(element: Element) -> UncertainDate:
     for sub_element in element.get_child_elements():
         if FamilyTree._has_tag(sub_element, Tag.Date):
             date, unparsed = Date.parse(sub_element.get_value())
             assert (date is not None and unparsed
                     == ""), f"Must parse date, but got {date, unparsed}"
             return date
     return None
示例#6
0
def create_event(tag_type: str, place: str = None, date: str = None, level: int = 1):
    event_element = Element(level, '', tag_type, '')
    if place is not None:
        event_place_element = Element(level + 1, '', tags.GEDCOM_TAG_PLACE, place)
        event_element.add_child_element(event_place_element)

    if date is not None:
        event_date_element = Element(level + 1, '', tags.GEDCOM_TAG_DATE, date)
        event_element.add_child_element(event_date_element)
    return event_element
示例#7
0
def element_equals(element1: Element, element2: Element):
    if not element_values_equals(element1, element2):
        print(f'{element1.to_gedcom_string()} != {element2.to_gedcom_string()}', file=sys.stderr)
        return False
    if len(element1.get_child_elements()) != len(element2.get_child_elements()):
        print(f'element1.len ({len(element1.get_child_elements())}) != '
              f'element2.len ({len(element2.get_child_elements())})', file=sys.stderr)
        return False
    child_elements_2 = element2.get_child_elements().copy()
    for e1 in element1.get_child_elements():
        found_match = False
        for e2 in child_elements_2:
            if element_values_equals(e1, e2):
                found_match = True
                child_elements_2.remove(e2)
                break
        if not found_match:
            print(f'No match found for element: {e1.to_gedcom_string()}', file=sys.stderr)
            return False
    return True
示例#8
0
 def __export_place(place: Place, event: Element):
     plac_element = event.new_child_element('PLAC', '', place.label)
     coordinates = place.get_property(PropertyTag.COORDINATE_LOCATION).value
     if coordinates.latitude and coordinates.longitude:
         map_element = plac_element.new_child_element('MAP')
         map_element.new_child_element(
             'LATI', '',
             '{}{}'.format('N' if coordinates.latitude > 0 else 'S',
                           abs(coordinates.latitude)))
         map_element.new_child_element(
             'LONG', '',
             '{}{}'.format('E' if coordinates.longitude > 0 else 'W',
                           abs(coordinates.longitude)))
示例#9
0
def create_individual(ptr: str,
                      level: int = 0,
                      name: str = None,
                      sex: str = None,
                      birth_place: str = None,
                      birth_date: str = None,
                      death_place: str = None,
                      death_date: str = None,
                      family_spouse_ptr: str = None,
                      family_child_ptr: str = None):
    individual_element = IndividualElement(level, ptr, tags.GEDCOM_TAG_INDIVIDUAL, '')
    if name is not None:
        individual_element.add_child_element(Element(level + 1, '', tags.GEDCOM_TAG_NAME, name))
    if sex is not None:
        individual_element.add_child_element(Element(level + 1, '', tags.GEDCOM_TAG_SEX, sex))
    if birth_place is not None or birth_date is not None:
        individual_element.add_child_element(create_event(tags.GEDCOM_TAG_BIRTH, birth_place, birth_date, level + 1))
    if death_place is not None or death_date is not None:
        individual_element.add_child_element(create_event(tags.GEDCOM_TAG_DEATH, death_place, death_date, level + 1))
    if family_spouse_ptr is not None:
        individual_element.add_child_element(Element(level + 1, '', tags.GEDCOM_TAG_FAMILY_SPOUSE, family_spouse_ptr))
    if family_child_ptr is not None:
        individual_element.add_child_element(Element(level + 1, '', tags.GEDCOM_TAG_FAMILY_CHILD, family_child_ptr))
    return individual_element
示例#10
0
 def create_family_element(self, family: Family):
     element = Element(0, '@{}@'.format(family.family_id), 'FAM', '')
     if family.father_id and family.father_id in self.elements.keys():
         element.new_child_element('HUSB', '',
                                   '@{}@'.format(family.father_id))
         self.elements[family.father_id].new_child_element(
             'FAMS', '', '@{}@'.format(family.family_id))
     if family.mother_id and family.mother_id in self.elements.keys():
         element.new_child_element('WIFE', '',
                                   '@{}@'.format(family.mother_id))
         self.elements[family.mother_id].new_child_element(
             'FAMS', '', '@{}@'.format(family.family_id))
     for child_id in family.children_ids:
         if child_id in self.database.cache.keys():
             element.new_child_element('CHIL', '', '@{}@'.format(child_id))
             self.elements[child_id].new_child_element(
                 'FAMC', '', '@{}@'.format(family.family_id))
     self.elements[family.family_id] = element
示例#11
0
    def test_filter_child_elements(self):
        individual = gen_test_individual()
        elements_with_name_tag = gedcom_helpers.filter_child_elements(
            individual, tag=tags.GEDCOM_TAG_NAME)
        for element in elements_with_name_tag:
            self.assertEqual(element.get_tag(), tags.GEDCOM_TAG_NAME)

        elements_with_name_value = gedcom_helpers.filter_child_elements(
            individual, value="/Some/ Guy")
        for element in elements_with_name_value:
            self.assertEqual(element.get_value(), '/Some/ Guy')

        # This is not a real case where a pointer would be used in GEDCOM, this is just for testing
        individual.add_child_element(
            Element(1, '@P1@', tags.GEDCOM_TAG_INDIVIDUAL, ''))
        elements_with_family_pointer = gedcom_helpers.filter_child_elements(
            individual, pointer="@P1@")
        for element in elements_with_family_pointer:
            self.assertEqual(element.get_pointer(), '@P1@')

        elements_with_tag_and_value = gedcom_helpers.filter_child_elements(
            individual, tag=tags.GEDCOM_TAG_SEX, value='M')
        for element in elements_with_tag_and_value:
            self.assertEqual(element.get_tag(), tags.GEDCOM_TAG_SEX)
            self.assertEqual(element.get_value(), 'M')

        match_tag_with_multiple_tags = gedcom_helpers \
            .filter_child_elements(individual, (tags.GEDCOM_TAG_NAME, tags.GEDCOM_TAG_SEX))
        for element in match_tag_with_multiple_tags:
            self.assertIn(element.get_tag(),
                          (tags.GEDCOM_TAG_NAME, tags.GEDCOM_TAG_SEX))

        # tags should not be empty, and we know this is true for the example
        no_elements = gedcom_helpers.filter_child_elements(individual, tag="")
        self.assertEqual(no_elements, [])

        contains_tag = gedcom_helpers.filter_child_elements(individual,
                                                            tag=True)
        for element in contains_tag:
            self.assertNotIn(element.get_tag(), ('', None))

        not_contains_value = gedcom_helpers.filter_child_elements(individual,
                                                                  value=False)
        for element in not_contains_value:
            self.assertIn(element.get_value(), ('', None))
示例#12
0
 def create_family_element(self, family: Family):
     if family.mother_id == 'Q271506':
         print('Q271506')
     element = Element(0, '@{}@'.format(family.id), 'FAM', '')
     if family.father_id and family.father_id in self.elements.keys():
         element.new_child_element('HUSB', '',
                                   '@{}@'.format(family.father_id))
         self.elements[family.father_id].new_child_element(
             'FAMS', '', '@{}@'.format(family.id))
     if family.mother_id and family.mother_id in self.elements.keys():
         element.new_child_element('WIFE', '',
                                   '@{}@'.format(family.mother_id))
         self.elements[family.mother_id].new_child_element(
             'FAMS', '', '@{}@'.format(family.id))
     for child_id in family.children_ids:
         if child_id in self.characters.keys():
             element.new_child_element('CHIL', '', '@{}@'.format(child_id))
             self.elements[child_id].new_child_element(
                 'FAMC', '', '@{}@'.format(family.id))
     self.elements[family.id] = element
示例#13
0
 def create_character_element(self, character: Character):
     element = Element(0, '@{}@'.format(character.id), 'INDI', '')
     name_element = element.new_child_element('NAME', '',
                                              str(character.label))
     if character.data.given_name and character.data.family_name:
         name_element.new_child_element('GIVN', '',
                                        character.data.given_name)
         name_element.new_child_element('SURN', '',
                                        character.data.family_name)
     if character.data.birth_date:
         birth_element = element.new_child_element('BIRT')
         birth_element.new_child_element('DATE', '',
                                         str(character.data.birth_date))
     if character.data.birth_date:
         death_element = element.new_child_element('DEAT')
         death_element.new_child_element('DATE', '',
                                         str(character.data.birth_date))
     if character.sex:
         element.new_child_element('SEX', '', character.sex)
     self.create_family(character)
     self.elements[character.id] = element
示例#14
0
 def test_element_values_equals(self):
     element_1 = Element(1, '', '', '')
     element_2 = Element(2, '', '', '')
     self.assertFalse(
         gedcom_helpers.element_values_equals(element_1, element_2))
     element_3 = Element(1, '', '', '')
     self.assertTrue(
         gedcom_helpers.element_values_equals(element_1, element_3))
     self.assertFalse(
         gedcom_helpers.element_values_equals(element_2, element_3))
     element_4 = Element(2, '', '', 'value')
     self.assertFalse(
         gedcom_helpers.element_values_equals(element_2, element_4))
     element_5 = Element(2, 'pointer', '', '')
     self.assertFalse(
         gedcom_helpers.element_values_equals(element_2, element_5))
     element_6 = Element(2, '', 'tag', '')
     self.assertFalse(
         gedcom_helpers.element_values_equals(element_2, element_6))
     element_7 = Element(2, 'pointer', 'tag', 'value')
     self.assertFalse(
         gedcom_helpers.element_values_equals(element_2, element_7))
示例#15
0
    def test_gen_head_and_submitter(self):
        user = User(username="******")
        tree = Tree(title="Test", creator=user)

        head, submitter = gedcom_generator.gen_head_and_submitter(tree)

        expected_head = Element(0, '', tags.GEDCOM_TAG_HEAD, '')
        charset_element = Element(1, '', tags.GEDCOM_TAG_CHARSET,
                                  tags.GEDCOM_CHARSET_UTF8)
        expected_head.add_child_element(charset_element)
        gedcom_element = Element(1, '', tags.GEDCOM_TAG_GEDCOM, '')
        version_element = Element(2, '', tags.GEDCOM_TAG_VERSION, '5.5')
        gedcom_element.add_child_element(version_element)
        format_element = Element(2, '', tags.GEDCOM_TAG_FORM, 'Lineage-Linked')
        gedcom_element.add_child_element(format_element)
        expected_head.add_child_element(gedcom_element)
        submitter_ptr = '@SUBMITTER@'
        expected_head.add_child_element(
            Element(1, '', tags.GEDCOM_TAG_SUBMITTER, submitter_ptr))
        expected_submitter = Element(0, submitter_ptr,
                                     tags.GEDCOM_TAG_SUBMITTER, '')
        expected_submitter.add_child_element(
            Element(1, '', tags.GEDCOM_TAG_NAME, tree.creator.username))

        self.assertTrue(gedcom_helpers.element_equals(head, expected_head))
        self.assertTrue(
            gedcom_helpers.element_equals(submitter, expected_submitter))
示例#16
0
 def get_create_child_by_tag(element: Element, tag: str):
     childs = element.get_child_elements()
     for child in childs:
         if child.get_tag() == tag:
             return child
     return element.new_child_element(tag)
示例#17
0
    def __parse_line(line_number, line, last_element, strict=True):
        """Parse a line from a GEDCOM 5.5 formatted document

        Each line should have the following (bracketed items optional):
        level + ' ' + [pointer + ' ' +] tag + [' ' + line_value]

        :type line_number: int
        :type line: str
        :type last_element: Element
        :type strict: bool

        :rtype: Element
        """

        # Level must start with non-negative int, no leading zeros.
        level_regex = '^(0|[1-9]+[0-9]*) '

        # Pointer optional, if it exists it must be flanked by `@`
        pointer_regex = '(@[^@]+@ |)'

        # Tag must be an alphanumeric string
        tag_regex = '([A-Za-z0-9_]+)'

        # Value optional, consists of anything after a space to end of line
        value_regex = '( [^\n\r]*|)'

        # End of line defined by `\n` or `\r`
        end_of_line_regex = '([\r\n]{1,2})'

        # Complete regex
        gedcom_line_regex = level_regex + pointer_regex + tag_regex + value_regex + end_of_line_regex
        regex_match = regex.match(gedcom_line_regex, line)

        if regex_match is None:
            if strict:
                error_message = (
                    "Line %d of document violates GEDCOM format 5.5" %
                    line_number +
                    "\nSee: https://chronoplexsoftware.com/gedcomvalidator/gedcom/gedcom-5.5.pdf"
                )
                raise GedcomFormatViolationError(error_message)
            else:
                # Quirk check - see if this is a line without a CRLF (which could be the last line)
                last_line_regex = level_regex + pointer_regex + tag_regex + value_regex
                regex_match = regex.match(last_line_regex, line)
                if regex_match is not None:
                    line_parts = regex_match.groups()

                    level = int(line_parts[0])
                    pointer = line_parts[1].rstrip(' ')
                    tag = line_parts[2]
                    value = line_parts[3][1:]
                    crlf = '\n'
                else:
                    # Quirk check - Sometimes a gedcom has a text field with a CR.
                    # This creates a line without the standard level and pointer.
                    # If this is detected then turn it into a CONC or CONT.
                    line_regex = '([^\n\r]*|)'
                    cont_line_regex = line_regex + end_of_line_regex
                    regex_match = regex.match(cont_line_regex, line)
                    line_parts = regex_match.groups()
                    level = last_element.get_level()
                    tag = last_element.get_tag()
                    pointer = None
                    value = line_parts[0][1:]
                    crlf = line_parts[1]
                    if tag != gedcom.tags.GEDCOM_TAG_CONTINUED and tag != gedcom.tags.GEDCOM_TAG_CONCATENATION:
                        # Increment level and change this line to a CONC
                        level += 1
                        tag = gedcom.tags.GEDCOM_TAG_CONCATENATION
        else:
            line_parts = regex_match.groups()

            level = int(line_parts[0])
            pointer = line_parts[1].rstrip(' ')
            tag = line_parts[2]
            value = line_parts[3][1:]
            crlf = line_parts[4]

        # Check level: should never be more than one higher than previous line.
        if level > last_element.get_level() + 1:
            error_message = (
                "Line %d of document violates GEDCOM format 5.5" % line_number
                +
                "\nLines must be no more than one level higher than previous line."
                +
                "\nSee: https://chronoplexsoftware.com/gedcomvalidator/gedcom/gedcom-5.5.pdf"
            )
            raise GedcomFormatViolationError(error_message)

        # Create element. Store in list and dict, create children and parents.
        if tag == gedcom.tags.GEDCOM_TAG_INDIVIDUAL:
            element = IndividualElement(level,
                                        pointer,
                                        tag,
                                        value,
                                        crlf,
                                        multi_line=False)
        elif tag == gedcom.tags.GEDCOM_TAG_FAMILY:
            element = FamilyElement(level,
                                    pointer,
                                    tag,
                                    value,
                                    crlf,
                                    multi_line=False)
        elif tag == gedcom.tags.GEDCOM_TAG_FILE:
            element = FileElement(level,
                                  pointer,
                                  tag,
                                  value,
                                  crlf,
                                  multi_line=False)
        elif tag == gedcom.tags.GEDCOM_TAG_OBJECT:
            element = ObjectElement(level,
                                    pointer,
                                    tag,
                                    value,
                                    crlf,
                                    multi_line=False)
        else:
            element = Element(level,
                              pointer,
                              tag,
                              value,
                              crlf,
                              multi_line=False)

        # Start with last element as parent, back up if necessary.
        parent_element = last_element

        while parent_element.get_level() > level - 1:
            parent_element = parent_element.get_parent_element()

        # Add child to parent & parent to child.
        parent_element.add_child_element(element)

        return element
示例#18
0
def element_values_equals(element1: Element, element2: Element):
    return element1.get_level() == element2.get_level() \
           and element1.get_pointer() == element2.get_pointer() \
           and element1.get_tag() == element2.get_tag() \
           and element1.get_value() == element2.get_value()
示例#19
0
 def print_element(self, file, element: Element, depth=0):
     gedcom_string = element.to_gedcom_string()
     file.write(gedcom_string)
     for child in element.get_child_elements():
         self.print_element(file, child, depth=depth + 1)
示例#20
0
 def _has_tag(element: Element, tag: Tag) -> bool:
     return element.get_tag() == tag.value
示例#21
0
def print_element(file, element: Element, depth=0):
    file.write(element.to_gedcom_string())
    for child in element.get_child_elements():
        print_element(file, child, depth=depth+1)
示例#22
0
def test_initialization():
    element = Element(level=-1, pointer="", tag="", value="")
    assert isinstance(element, Element)