Module containing functions for detecting GEDCOM file encoding and version.
+
+
+Expand source code
+
+
# -*- coding: utf-8 -*-
+
+# Python GEDCOM Parser
+#
+# Copyright (C) 2020 Christopher Horn (cdhorn at embarqmail dot com)
+# Copyright (C) 2018 Damon Brodie (damon.brodie at gmail.com)
+# Copyright (C) 2018-2019 Nicklas Reincke (contact at reynke.com)
+# Copyright (C) 2016 Andreas Oberritter
+# Copyright (C) 2012 Madeleine Price Ball
+# Copyright (C) 2005 Daniel Zappala (zappala at cs.byu.edu)
+# Copyright (C) 2005 Brigham Young University
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Further information about the license: http://www.gnu.org/licenses/gpl-2.0.html
+
+"""
+Module containing functions for detecting GEDCOM file encoding and version.
+"""
+
+from typing import Tuple
+import chardet
+import ansel
+
+import gedcom.tags as tags
+import gedcom.standards as standards
+from gedcom.errors import GedcomFormatViolationError
+from gedcom.errors import GedcomCharacterSetUnsupportedError
+
+ansel.register()
+
+
+def __validate_encoding(file_path, codec):
+ """Check the encoding is compatible with the encoding as reported by the
+ `gedcom.tags.GEDCOM_TAG_CHARACTER` header tag.
+ """
+ with open(file_path, 'r', encoding=codec) as gedcom_data:
+ for line in gedcom_data:
+ if tags.GEDCOM_TAG_CHARACTER in line:
+ character_set = line.split(' ')[2].lower().strip()
+ break
+
+ if character_set == 'ansel' and codec == 'gedcom':
+ return
+
+ if character_set == 'ascii' and codec == 'utf-8':
+ return
+
+ if character_set not in codec:
+ errmsg = "A " + codec + " encoding was detected but the GEDCOM reports using " + \
+ "a " + character_set + " encoding.\n" + \
+ "Processing aborted as unsure how to properly proceed.\n" + \
+ "See: {0}".format(standards.GEDCOM_5_5_1)
+ raise GedcomCharacterSetUnsupportedError(errmsg)
+
+
+def get_encoding(file_path: str) -> str:
+ """Probe a GEDCOM file to determine the encoding and validate it against the encoding
+ as reported in the `HEADER` record by the `gedcom.tags.GEDCOM_TAG_CHARACTER` tag.
+
+ Returns: codec
+ """
+ with open(file_path, 'rb') as gedcom_data:
+ sample_data = gedcom_data.read(262144)
+
+ # Note chardet reports Ansel as ISO-8859-1 or ISO-8859-2 at this time
+ # depending on sample size, and could be making a faulty assumption here
+ # by treating it as Ansel. The ansel module supports both ansel and a
+ # gedcom codec with some gedcom specific extensions so we use that.
+ codec = 'unknown'
+ probe = chardet.detect(sample_data)
+ if probe['encoding'] in ['UTF-8', 'UTF-8-SIG']:
+ codec = 'utf-8-sig'
+ elif probe['encoding'] == 'UTF-16':
+ codec = 'utf-16'
+ elif probe['encoding'] == 'ASCII':
+ codec = 'ascii'
+ elif probe['encoding'] == 'ANSEL':
+ codec = 'ansel'
+ elif 'ISO-8859' in probe['encoding']:
+ codec = 'gedcom'
+
+ if codec == 'unknown':
+ errmsg = "Unable to properly identify a supported GEDCOM character encoding for" + \
+ "the file.\nSee: {0}".format(standards.GEDCOM_5_5_1)
+ raise GedcomCharacterSetUnsupportedError(errmsg)
+
+ __validate_encoding(file_path, codec)
+ return codec
+
+
+def get_version(file_path: str, codec: str) -> Tuple[str, str, str]:
+ """Probe a GEDCOM file to identify the version of the standard used as some reported 5.5
+ files are really 5.5.1.
+
+ Returns: probed version, reported version, reported format
+ """
+ in_gedc_tag = False
+ gedcom_version = None
+ gedcom_format = None
+ with open(file_path, 'r', encoding=codec) as gedcom_data:
+ for line in gedcom_data:
+ if '1 GEDC' in line:
+ in_gedc_tag = True
+ continue
+ if in_gedc_tag:
+ if '2 VERS' in line:
+ gedcom_version = line.split(' ')[2].strip()
+ continue
+ if '2 FORM' in line:
+ gedcom_format = line.split(' ')[2].strip()
+ break
+
+ if gedcom_version is None or gedcom_format is None:
+ errmsg = "Malformed GEDCOM file, the required version number or format were" + \
+ " not found as expected.\nSee: {0}".format(standards.GEDCOM_5_5_1)
+ raise GedcomFormatViolationError(errmsg)
+
+ probed_version = gedcom_version
+
+ # UTF was added in the 5.5.1 specification
+ if gedcom_version == '5.5' and 'utf' in codec:
+ probed_version = gedcom_version
+
+ return probed_version, gedcom_version, gedcom_format
+
+
+
+
+
+
+
+
Functions
+
+
+def get_encoding(file_path: str) -> str
+
+
+
Probe a GEDCOM file to determine the encoding and validate it against the encoding
+as reported in the HEADER record by the GEDCOM_TAG_CHARACTER tag.
+
Returns: codec
+
+
+Expand source code
+
+
def get_encoding(file_path: str) -> str:
+ """Probe a GEDCOM file to determine the encoding and validate it against the encoding
+ as reported in the `HEADER` record by the `gedcom.tags.GEDCOM_TAG_CHARACTER` tag.
+
+ Returns: codec
+ """
+ with open(file_path, 'rb') as gedcom_data:
+ sample_data = gedcom_data.read(262144)
+
+ # Note chardet reports Ansel as ISO-8859-1 or ISO-8859-2 at this time
+ # depending on sample size, and could be making a faulty assumption here
+ # by treating it as Ansel. The ansel module supports both ansel and a
+ # gedcom codec with some gedcom specific extensions so we use that.
+ codec = 'unknown'
+ probe = chardet.detect(sample_data)
+ if probe['encoding'] in ['UTF-8', 'UTF-8-SIG']:
+ codec = 'utf-8-sig'
+ elif probe['encoding'] == 'UTF-16':
+ codec = 'utf-16'
+ elif probe['encoding'] == 'ASCII':
+ codec = 'ascii'
+ elif probe['encoding'] == 'ANSEL':
+ codec = 'ansel'
+ elif 'ISO-8859' in probe['encoding']:
+ codec = 'gedcom'
+
+ if codec == 'unknown':
+ errmsg = "Unable to properly identify a supported GEDCOM character encoding for" + \
+ "the file.\nSee: {0}".format(standards.GEDCOM_5_5_1)
+ raise GedcomCharacterSetUnsupportedError(errmsg)
+
+ __validate_encoding(file_path, codec)
+ return codec
Probe a GEDCOM file to identify the version of the standard used as some reported 5.5
+files are really 5.5.1.
+
Returns: probed version, reported version, reported format
+
+
+Expand source code
+
+
def get_version(file_path: str, codec: str) -> Tuple[str, str, str]:
+ """Probe a GEDCOM file to identify the version of the standard used as some reported 5.5
+ files are really 5.5.1.
+
+ Returns: probed version, reported version, reported format
+ """
+ in_gedc_tag = False
+ gedcom_version = None
+ gedcom_format = None
+ with open(file_path, 'r', encoding=codec) as gedcom_data:
+ for line in gedcom_data:
+ if '1 GEDC' in line:
+ in_gedc_tag = True
+ continue
+ if in_gedc_tag:
+ if '2 VERS' in line:
+ gedcom_version = line.split(' ')[2].strip()
+ continue
+ if '2 FORM' in line:
+ gedcom_format = line.split(' ')[2].strip()
+ break
+
+ if gedcom_version is None or gedcom_format is None:
+ errmsg = "Malformed GEDCOM file, the required version number or format were" + \
+ " not found as expected.\nSee: {0}".format(standards.GEDCOM_5_5_1)
+ raise GedcomFormatViolationError(errmsg)
+
+ probed_version = gedcom_version
+
+ # UTF was added in the 5.5.1 specification
+ if gedcom_version == '5.5' and 'utf' in codec:
+ probed_version = gedcom_version
+
+ return probed_version, gedcom_version, gedcom_format
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/gedcom/element/element.html b/docs/gedcom/element/element.html
index 7d9c271..5e91e48 100644
--- a/docs/gedcom/element/element.html
+++ b/docs/gedcom/element/element.html
@@ -3,14 +3,14 @@
-
+
gedcom.element.element API documentation
-
+
-
-
+
+
@@ -20,7 +20,7 @@
Module gedcom.element.element
-
Base GEDCOM element
+
Base GEDCOM element.
Expand source code
@@ -53,18 +53,20 @@
Module gedcom.element.element
# Further information about the license: http://www.gnu.org/licenses/gpl-2.0.html
"""
-Base GEDCOM element
+Base GEDCOM element.
"""
from sys import version_info
+from typing import List
+
from gedcom.helpers import deprecated
import gedcom.tags
class Element(object):
- """GEDCOM element
+ """GEDCOM element.
- Each line in a GEDCOM file is an element with the format
+ Each line in a GEDCOM file is an element with the format:
`level [pointer] tag [value]`
@@ -89,7 +91,8 @@
Module gedcom.element.element
Tags available to an element are seen here: `gedcom.tags`
"""
- def __init__(self, level, pointer, tag, value, crlf="\n", multi_line=True):
+ def __init__(self, level: int, pointer: str, tag: str, value: str,
+ crlf: str = "\n", multi_line: bool = True):
# basic element info
self.__level = level
self.__pointer = pointer
@@ -104,39 +107,33 @@
Module gedcom.element.element
if multi_line:
self.set_multi_line_value(value)
- def get_level(self):
- """Returns the level of this element from within the GEDCOM file
- :rtype: int
+ def get_level(self) -> int:
+ """Returns the level of this element from within the GEDCOM file.
"""
return self.__level
- def get_pointer(self):
- """Returns the pointer of this element from within the GEDCOM file
- :rtype: str
+ def get_pointer(self) -> str:
+ """Returns the pointer of this element from within the GEDCOM file.
"""
return self.__pointer
- def get_tag(self):
- """Returns the tag of this element from within the GEDCOM file
- :rtype: str
+ def get_tag(self) -> str:
+ """Returns the tag of this element from within the GEDCOM file.
"""
return self.__tag
- def get_value(self):
- """Return the value of this element from within the GEDCOM file
- :rtype: str
+ def get_value(self) -> str:
+ """Return the value of this element from within the GEDCOM file.
"""
return self.__value
- def set_value(self, value):
- """Sets the value of this element
- :type value: str
+ def set_value(self, value: str):
+ """Sets the value of this element.
"""
self.__value = value
- def get_multi_line_value(self):
- """Returns the value of this element including concatenations or continuations
- :rtype: str
+ def get_multi_line_value(self) -> str:
+ """Returns the value of this element including concatenations or continuations.
"""
result = self.get_value()
last_crlf = self.__crlf
@@ -150,17 +147,14 @@
Module gedcom.element.element
last_crlf = element.__crlf
return result
- def __available_characters(self):
+ def __available_characters(self) -> int:
"""Get the number of available characters of the elements original string
- :rtype: int
"""
element_characters = len(self.to_gedcom_string())
return 0 if element_characters > 255 else 255 - element_characters
- def __line_length(self, line):
- """@TODO Write docs.
- :type line: str
- :rtype: int
+ def __line_length(self, line: str) -> int:
+ """Return line length.
"""
total_characters = len(line)
available_characters = self.__available_characters()
@@ -173,40 +167,36 @@
Module gedcom.element.element
return available_characters
return available_characters - spaces
- def __set_bounded_value(self, value):
+ def __set_bounded_value(self, value: str) -> int:
"""@TODO Write docs.
- :type value: str
- :rtype: int
"""
line_length = self.__line_length(value)
self.set_value(value[:line_length])
return line_length
- def __add_bounded_child(self, tag, value):
+ def __add_bounded_child(self, tag: str, value: str) -> int:
"""@TODO Write docs.
- :type tag: str
- :type value: str
- :rtype: int
"""
child = self.new_child_element(tag)
return child.__set_bounded_value(value)
- def __add_concatenation(self, string):
+ def __add_concatenation(self, string: str):
"""@TODO Write docs.
- :rtype: str
"""
index = 0
size = len(string)
while index < size:
index += self.__add_bounded_child(gedcom.tags.GEDCOM_TAG_CONCATENATION, string[index:])
- def set_multi_line_value(self, value):
- """Sets the value of this element, adding concatenation and continuation lines when necessary
- :type value: str
+ def set_multi_line_value(self, value: str):
+ """Sets the value of this element, adding concatenation and continuation lines
+ when necessary.
"""
self.set_value('')
self.get_child_elements()[:] = [child for child in self.get_child_elements() if
- child.get_tag() not in (gedcom.tags.GEDCOM_TAG_CONCATENATION, gedcom.tags.GEDCOM_TAG_CONTINUED)]
+ child.get_tag() not in
+ (gedcom.tags.GEDCOM_TAG_CONCATENATION,
+ gedcom.tags.GEDCOM_TAG_CONTINUED)]
lines = value.splitlines()
if lines:
@@ -218,79 +208,91 @@
Module gedcom.element.element
n = self.__add_bounded_child(gedcom.tags.GEDCOM_TAG_CONTINUED, line)
self.__add_concatenation(line[n:])
- def get_child_elements(self):
- """Returns the direct child elements of this element
- :rtype: list of Element
+ def get_child_elements(self) -> List['Element']:
+ """Returns the direct child elements of this element.
"""
return self.__children
- def new_child_element(self, tag, pointer="", value=""):
- """Creates and returns a new child element of this element
-
- :type tag: str
- :type pointer: str
- :type value: str
- :rtype: Element
+ def new_child_element(self, tag: str, pointer: str = "",
+ value: str = "") -> 'Element':
+ """Creates and returns a new child element of this element.
"""
from gedcom.element.family import FamilyElement
- from gedcom.element.file import FileElement
from gedcom.element.individual import IndividualElement
+ from gedcom.element.note import NoteElement
from gedcom.element.object import ObjectElement
+ from gedcom.element.repository import RepositoryElement
+ from gedcom.element.source import SourceElement
+ from gedcom.element.submitter import SubmitterElement
+ from gedcom.element.submission import SubmissionElement
+ from gedcom.element.header import HeaderElement
# Differentiate between the type of the new child element
if tag == gedcom.tags.GEDCOM_TAG_FAMILY:
- child_element = FamilyElement(self.get_level() + 1, pointer, tag, value, self.__crlf)
- elif tag == gedcom.tags.GEDCOM_TAG_FILE:
- child_element = FileElement(self.get_level() + 1, pointer, tag, value, self.__crlf)
+ child_element = FamilyElement(self.get_level() + 1, pointer, tag,
+ value, self.__crlf)
elif tag == gedcom.tags.GEDCOM_TAG_INDIVIDUAL:
- child_element = IndividualElement(self.get_level() + 1, pointer, tag, value, self.__crlf)
+ child_element = IndividualElement(self.get_level() + 1, pointer, tag,
+ value, self.__crlf)
+ elif tag == gedcom.tags.GEDCOM_TAG_NOTE:
+ child_element = NoteElement(self.get_level() + 1, pointer, tag,
+ value, self.__crlf)
elif tag == gedcom.tags.GEDCOM_TAG_OBJECT:
- child_element = ObjectElement(self.get_level() + 1, pointer, tag, value, self.__crlf)
+ child_element = ObjectElement(self.get_level() + 1, pointer, tag,
+ value, self.__crlf)
+ elif tag == gedcom.tags.GEDCOM_TAG_REPOSITORY:
+ child_element = RepositoryElement(self.get_level() + 1, pointer, tag,
+ value, self.__crlf)
+ elif tag == gedcom.tags.GEDCOM_TAG_SOURCE:
+ child_element = SourceElement(self.get_level() + 1, pointer, tag,
+ value, self.__crlf)
+ elif tag == gedcom.tags.GEDCOM_TAG_SUBMITTER:
+ child_element = SubmitterElement(self.get_level() + 1, pointer, tag,
+ value, self.__crlf)
+ elif tag == gedcom.tags.GEDCOM_TAG_SUBMISSION:
+ child_element = SubmissionElement(self.get_level() + 1, pointer, tag,
+ value, self.__crlf)
+ elif tag == gedcom.tags.GEDCOM_TAG_HEADER:
+ child_element = HeaderElement(self.get_level() + 1, pointer, tag,
+ value, self.__crlf)
else:
- child_element = Element(self.get_level() + 1, pointer, tag, value, self.__crlf)
+ child_element = Element(self.get_level() + 1, pointer, tag,
+ value, self.__crlf)
self.add_child_element(child_element)
return child_element
- def add_child_element(self, element):
- """Adds a child element to this element
-
- :type element: Element
+ def add_child_element(self, element: 'Element'):
+ """Adds a child element to this element.
"""
self.get_child_elements().append(element)
element.set_parent_element(self)
return element
- def get_parent_element(self):
- """Returns the parent element of this element
- :rtype: Element
+ def get_parent_element(self) -> 'Element':
+ """Returns the parent element of this element.
"""
return self.__parent
- def set_parent_element(self, element):
- """Adds a parent element to this element
+ def set_parent_element(self, element: 'Element'):
+ """Adds a parent element to this element.
There's usually no need to call this method manually,
`add_child_element()` calls it automatically.
-
- :type element: Element
"""
self.__parent = element
@deprecated
- def get_individual(self):
- """Returns this element and all of its sub-elements represented as a GEDCOM string
+ def get_individual(self) -> str:
+ """Returns this element and all of its sub-elements represented as a GEDCOM string.
::deprecated:: As of version 1.0.0 use `to_gedcom_string()` method instead
- :rtype: str
"""
return self.to_gedcom_string(True)
- def to_gedcom_string(self, recursive=False):
- """Formats this element and optionally all of its sub-elements into a GEDCOM string
- :type recursive: bool
- :rtype: str
+ def to_gedcom_string(self, recursive: bool = False) -> str:
+ """Formats this element and optionally all of its sub-elements into a GEDCOM string.
"""
result = str(self.get_level())
@@ -314,7 +316,7 @@
Each line in a GEDCOM file is an element with the format
+
GEDCOM element.
+
Each line in a GEDCOM file is an element with the format:
level [pointer] tag [value]
where level and tag are required, and pointer and value are
optional.
@@ -356,15 +358,15 @@
Classes
that points to a family record in which the associated person is a
child.
See a GEDCOM file for examples of tags and their values.
-
Tags available to an element are seen here: gedcom.tags
+
Tags available to an element are seen here: gedcom.tags
Expand source code
class Element(object):
- """GEDCOM element
+ """GEDCOM element.
- Each line in a GEDCOM file is an element with the format
+ Each line in a GEDCOM file is an element with the format:
`level [pointer] tag [value]`
@@ -389,7 +391,8 @@
Classes
Tags available to an element are seen here: `gedcom.tags`
"""
- def __init__(self, level, pointer, tag, value, crlf="\n", multi_line=True):
+ def __init__(self, level: int, pointer: str, tag: str, value: str,
+ crlf: str = "\n", multi_line: bool = True):
# basic element info
self.__level = level
self.__pointer = pointer
@@ -404,39 +407,33 @@
Classes
if multi_line:
self.set_multi_line_value(value)
- def get_level(self):
- """Returns the level of this element from within the GEDCOM file
- :rtype: int
+ def get_level(self) -> int:
+ """Returns the level of this element from within the GEDCOM file.
"""
return self.__level
- def get_pointer(self):
- """Returns the pointer of this element from within the GEDCOM file
- :rtype: str
+ def get_pointer(self) -> str:
+ """Returns the pointer of this element from within the GEDCOM file.
"""
return self.__pointer
- def get_tag(self):
- """Returns the tag of this element from within the GEDCOM file
- :rtype: str
+ def get_tag(self) -> str:
+ """Returns the tag of this element from within the GEDCOM file.
"""
return self.__tag
- def get_value(self):
- """Return the value of this element from within the GEDCOM file
- :rtype: str
+ def get_value(self) -> str:
+ """Return the value of this element from within the GEDCOM file.
"""
return self.__value
- def set_value(self, value):
- """Sets the value of this element
- :type value: str
+ def set_value(self, value: str):
+ """Sets the value of this element.
"""
self.__value = value
- def get_multi_line_value(self):
- """Returns the value of this element including concatenations or continuations
- :rtype: str
+ def get_multi_line_value(self) -> str:
+ """Returns the value of this element including concatenations or continuations.
"""
result = self.get_value()
last_crlf = self.__crlf
@@ -450,17 +447,14 @@
Classes
last_crlf = element.__crlf
return result
- def __available_characters(self):
+ def __available_characters(self) -> int:
"""Get the number of available characters of the elements original string
- :rtype: int
"""
element_characters = len(self.to_gedcom_string())
return 0 if element_characters > 255 else 255 - element_characters
- def __line_length(self, line):
- """@TODO Write docs.
- :type line: str
- :rtype: int
+ def __line_length(self, line: str) -> int:
+ """Return line length.
"""
total_characters = len(line)
available_characters = self.__available_characters()
@@ -473,40 +467,36 @@
Classes
return available_characters
return available_characters - spaces
- def __set_bounded_value(self, value):
+ def __set_bounded_value(self, value: str) -> int:
"""@TODO Write docs.
- :type value: str
- :rtype: int
"""
line_length = self.__line_length(value)
self.set_value(value[:line_length])
return line_length
- def __add_bounded_child(self, tag, value):
+ def __add_bounded_child(self, tag: str, value: str) -> int:
"""@TODO Write docs.
- :type tag: str
- :type value: str
- :rtype: int
"""
child = self.new_child_element(tag)
return child.__set_bounded_value(value)
- def __add_concatenation(self, string):
+ def __add_concatenation(self, string: str):
"""@TODO Write docs.
- :rtype: str
"""
index = 0
size = len(string)
while index < size:
index += self.__add_bounded_child(gedcom.tags.GEDCOM_TAG_CONCATENATION, string[index:])
- def set_multi_line_value(self, value):
- """Sets the value of this element, adding concatenation and continuation lines when necessary
- :type value: str
+ def set_multi_line_value(self, value: str):
+ """Sets the value of this element, adding concatenation and continuation lines
+ when necessary.
"""
self.set_value('')
self.get_child_elements()[:] = [child for child in self.get_child_elements() if
- child.get_tag() not in (gedcom.tags.GEDCOM_TAG_CONCATENATION, gedcom.tags.GEDCOM_TAG_CONTINUED)]
+ child.get_tag() not in
+ (gedcom.tags.GEDCOM_TAG_CONCATENATION,
+ gedcom.tags.GEDCOM_TAG_CONTINUED)]
lines = value.splitlines()
if lines:
@@ -518,79 +508,91 @@
Classes
n = self.__add_bounded_child(gedcom.tags.GEDCOM_TAG_CONTINUED, line)
self.__add_concatenation(line[n:])
- def get_child_elements(self):
- """Returns the direct child elements of this element
- :rtype: list of Element
+ def get_child_elements(self) -> List['Element']:
+ """Returns the direct child elements of this element.
"""
return self.__children
- def new_child_element(self, tag, pointer="", value=""):
- """Creates and returns a new child element of this element
-
- :type tag: str
- :type pointer: str
- :type value: str
- :rtype: Element
+ def new_child_element(self, tag: str, pointer: str = "",
+ value: str = "") -> 'Element':
+ """Creates and returns a new child element of this element.
"""
from gedcom.element.family import FamilyElement
- from gedcom.element.file import FileElement
from gedcom.element.individual import IndividualElement
+ from gedcom.element.note import NoteElement
from gedcom.element.object import ObjectElement
+ from gedcom.element.repository import RepositoryElement
+ from gedcom.element.source import SourceElement
+ from gedcom.element.submitter import SubmitterElement
+ from gedcom.element.submission import SubmissionElement
+ from gedcom.element.header import HeaderElement
# Differentiate between the type of the new child element
if tag == gedcom.tags.GEDCOM_TAG_FAMILY:
- child_element = FamilyElement(self.get_level() + 1, pointer, tag, value, self.__crlf)
- elif tag == gedcom.tags.GEDCOM_TAG_FILE:
- child_element = FileElement(self.get_level() + 1, pointer, tag, value, self.__crlf)
+ child_element = FamilyElement(self.get_level() + 1, pointer, tag,
+ value, self.__crlf)
elif tag == gedcom.tags.GEDCOM_TAG_INDIVIDUAL:
- child_element = IndividualElement(self.get_level() + 1, pointer, tag, value, self.__crlf)
+ child_element = IndividualElement(self.get_level() + 1, pointer, tag,
+ value, self.__crlf)
+ elif tag == gedcom.tags.GEDCOM_TAG_NOTE:
+ child_element = NoteElement(self.get_level() + 1, pointer, tag,
+ value, self.__crlf)
elif tag == gedcom.tags.GEDCOM_TAG_OBJECT:
- child_element = ObjectElement(self.get_level() + 1, pointer, tag, value, self.__crlf)
+ child_element = ObjectElement(self.get_level() + 1, pointer, tag,
+ value, self.__crlf)
+ elif tag == gedcom.tags.GEDCOM_TAG_REPOSITORY:
+ child_element = RepositoryElement(self.get_level() + 1, pointer, tag,
+ value, self.__crlf)
+ elif tag == gedcom.tags.GEDCOM_TAG_SOURCE:
+ child_element = SourceElement(self.get_level() + 1, pointer, tag,
+ value, self.__crlf)
+ elif tag == gedcom.tags.GEDCOM_TAG_SUBMITTER:
+ child_element = SubmitterElement(self.get_level() + 1, pointer, tag,
+ value, self.__crlf)
+ elif tag == gedcom.tags.GEDCOM_TAG_SUBMISSION:
+ child_element = SubmissionElement(self.get_level() + 1, pointer, tag,
+ value, self.__crlf)
+ elif tag == gedcom.tags.GEDCOM_TAG_HEADER:
+ child_element = HeaderElement(self.get_level() + 1, pointer, tag,
+ value, self.__crlf)
else:
- child_element = Element(self.get_level() + 1, pointer, tag, value, self.__crlf)
+ child_element = Element(self.get_level() + 1, pointer, tag,
+ value, self.__crlf)
self.add_child_element(child_element)
return child_element
- def add_child_element(self, element):
- """Adds a child element to this element
-
- :type element: Element
+ def add_child_element(self, element: 'Element'):
+ """Adds a child element to this element.
"""
self.get_child_elements().append(element)
element.set_parent_element(self)
return element
- def get_parent_element(self):
- """Returns the parent element of this element
- :rtype: Element
+ def get_parent_element(self) -> 'Element':
+ """Returns the parent element of this element.
"""
return self.__parent
- def set_parent_element(self, element):
- """Adds a parent element to this element
+ def set_parent_element(self, element: 'Element'):
+ """Adds a parent element to this element.
There's usually no need to call this method manually,
`add_child_element()` calls it automatically.
-
- :type element: Element
"""
self.__parent = element
@deprecated
- def get_individual(self):
- """Returns this element and all of its sub-elements represented as a GEDCOM string
+ def get_individual(self) -> str:
+ """Returns this element and all of its sub-elements represented as a GEDCOM string.
::deprecated:: As of version 1.0.0 use `to_gedcom_string()` method instead
- :rtype: str
"""
return self.to_gedcom_string(True)
- def to_gedcom_string(self, recursive=False):
- """Formats this element and optionally all of its sub-elements into a GEDCOM string
- :type recursive: bool
- :rtype: str
+ def to_gedcom_string(self, recursive: bool = False) -> str:
+ """Formats this element and optionally all of its sub-elements into a GEDCOM string.
"""
result = str(self.get_level())
@@ -614,7 +616,7 @@
def add_child_element(self, element):
- """Adds a child element to this element
-
- :type element: Element
+
def add_child_element(self, element: 'Element'):
+ """Adds a child element to this element.
"""
self.get_child_elements().append(element)
element.set_parent_element(self)
@@ -653,72 +657,64 @@
Returns this element and all of its sub-elements represented as a GEDCOM string
-::deprecated:: As of version 1.0.0 use to_gedcom_string() method instead
-:rtype: str
+
Returns this element and all of its sub-elements represented as a GEDCOM string.
+::deprecated:: As of version 1.0.0 use to_gedcom_string() method instead
Expand source code
@deprecated
-def get_individual(self):
- """Returns this element and all of its sub-elements represented as a GEDCOM string
+def get_individual(self) -> str:
+ """Returns this element and all of its sub-elements represented as a GEDCOM string.
::deprecated:: As of version 1.0.0 use `to_gedcom_string()` method instead
- :rtype: str
"""
return self.to_gedcom_string(True)
-def get_level(self)
+def get_level(self) -> int
-
Returns the level of this element from within the GEDCOM file
-:rtype: int
+
Returns the level of this element from within the GEDCOM file.
Expand source code
-
def get_level(self):
- """Returns the level of this element from within the GEDCOM file
- :rtype: int
+
def get_level(self) -> int:
+ """Returns the level of this element from within the GEDCOM file.
"""
return self.__level
Returns the value of this element including concatenations or continuations
-:rtype: str
+
Returns the value of this element including concatenations or continuations.
Expand source code
-
def get_multi_line_value(self):
- """Returns the value of this element including concatenations or continuations
- :rtype: str
+
def get_multi_line_value(self) -> str:
+ """Returns the value of this element including concatenations or continuations.
"""
result = self.get_value()
last_crlf = self.__crlf
@@ -734,110 +730,119 @@
Methods
-def get_parent_element(self)
+def get_parent_element(self) -> Element
-
Returns the parent element of this element
-:rtype: Element
+
Returns the parent element of this element.
Expand source code
-
def get_parent_element(self):
- """Returns the parent element of this element
- :rtype: Element
+
def get_parent_element(self) -> 'Element':
+ """Returns the parent element of this element.
"""
return self.__parent
Creates and returns a new child element of this element.
Expand source code
-
def new_child_element(self, tag, pointer="", value=""):
- """Creates and returns a new child element of this element
-
- :type tag: str
- :type pointer: str
- :type value: str
- :rtype: Element
+
def new_child_element(self, tag: str, pointer: str = "",
+ value: str = "") -> 'Element':
+ """Creates and returns a new child element of this element.
"""
from gedcom.element.family import FamilyElement
- from gedcom.element.file import FileElement
from gedcom.element.individual import IndividualElement
+ from gedcom.element.note import NoteElement
from gedcom.element.object import ObjectElement
+ from gedcom.element.repository import RepositoryElement
+ from gedcom.element.source import SourceElement
+ from gedcom.element.submitter import SubmitterElement
+ from gedcom.element.submission import SubmissionElement
+ from gedcom.element.header import HeaderElement
# Differentiate between the type of the new child element
if tag == gedcom.tags.GEDCOM_TAG_FAMILY:
- child_element = FamilyElement(self.get_level() + 1, pointer, tag, value, self.__crlf)
- elif tag == gedcom.tags.GEDCOM_TAG_FILE:
- child_element = FileElement(self.get_level() + 1, pointer, tag, value, self.__crlf)
+ child_element = FamilyElement(self.get_level() + 1, pointer, tag,
+ value, self.__crlf)
elif tag == gedcom.tags.GEDCOM_TAG_INDIVIDUAL:
- child_element = IndividualElement(self.get_level() + 1, pointer, tag, value, self.__crlf)
+ child_element = IndividualElement(self.get_level() + 1, pointer, tag,
+ value, self.__crlf)
+ elif tag == gedcom.tags.GEDCOM_TAG_NOTE:
+ child_element = NoteElement(self.get_level() + 1, pointer, tag,
+ value, self.__crlf)
elif tag == gedcom.tags.GEDCOM_TAG_OBJECT:
- child_element = ObjectElement(self.get_level() + 1, pointer, tag, value, self.__crlf)
+ child_element = ObjectElement(self.get_level() + 1, pointer, tag,
+ value, self.__crlf)
+ elif tag == gedcom.tags.GEDCOM_TAG_REPOSITORY:
+ child_element = RepositoryElement(self.get_level() + 1, pointer, tag,
+ value, self.__crlf)
+ elif tag == gedcom.tags.GEDCOM_TAG_SOURCE:
+ child_element = SourceElement(self.get_level() + 1, pointer, tag,
+ value, self.__crlf)
+ elif tag == gedcom.tags.GEDCOM_TAG_SUBMITTER:
+ child_element = SubmitterElement(self.get_level() + 1, pointer, tag,
+ value, self.__crlf)
+ elif tag == gedcom.tags.GEDCOM_TAG_SUBMISSION:
+ child_element = SubmissionElement(self.get_level() + 1, pointer, tag,
+ value, self.__crlf)
+ elif tag == gedcom.tags.GEDCOM_TAG_HEADER:
+ child_element = HeaderElement(self.get_level() + 1, pointer, tag,
+ value, self.__crlf)
else:
- child_element = Element(self.get_level() + 1, pointer, tag, value, self.__crlf)
+ child_element = Element(self.get_level() + 1, pointer, tag,
+ value, self.__crlf)
self.add_child_element(child_element)
@@ -845,22 +850,24 @@
Sets the value of this element, adding concatenation and continuation lines when necessary
-:type value: str
+
Sets the value of this element, adding concatenation and continuation lines
+when necessary.
Expand source code
-
def set_multi_line_value(self, value):
- """Sets the value of this element, adding concatenation and continuation lines when necessary
- :type value: str
+
def set_multi_line_value(self, value: str):
+ """Sets the value of this element, adding concatenation and continuation lines
+ when necessary.
"""
self.set_value('')
self.get_child_elements()[:] = [child for child in self.get_child_elements() if
- child.get_tag() not in (gedcom.tags.GEDCOM_TAG_CONCATENATION, gedcom.tags.GEDCOM_TAG_CONTINUED)]
+ child.get_tag() not in
+ (gedcom.tags.GEDCOM_TAG_CONCATENATION,
+ gedcom.tags.GEDCOM_TAG_CONTINUED)]
lines = value.splitlines()
if lines:
@@ -874,60 +881,51 @@
There's usually no need to call this method manually,
-add_child_element() calls it automatically.
-
:type element: Element
+add_child_element() calls it automatically.
Expand source code
-
def set_parent_element(self, element):
- """Adds a parent element to this element
+
def set_parent_element(self, element: 'Element'):
+ """Adds a parent element to this element.
There's usually no need to call this method manually,
`add_child_element()` calls it automatically.
-
- :type element: Element
"""
self.__parent = element
Formats this element and optionally all of its sub-elements into a GEDCOM string
-:type recursive: bool
-:rtype: str
+
Formats this element and optionally all of its sub-elements into a GEDCOM string.
Expand source code
-
def to_gedcom_string(self, recursive=False):
- """Formats this element and optionally all of its sub-elements into a GEDCOM string
- :type recursive: bool
- :rtype: str
+
def to_gedcom_string(self, recursive: bool = False) -> str:
+ """Formats this element and optionally all of its sub-elements into a GEDCOM string.
"""
result = str(self.get_level())
@@ -995,7 +993,7 @@
Each line in a GEDCOM file is an element with the format
-
level [pointer] tag [value]
-
where level and tag are required, and pointer and value are
-optional.
-Elements are arranged hierarchically according to their
-level, and elements with a level of zero are at the top level.
-Elements with a level greater than zero are children of their
-parent.
-
A pointer has the format @pname@, where pname is any sequence of
-characters and numbers. The pointer identifies the object being
-pointed to, so that any pointer included as the value of any
-element points back to the original object.
-For example, an
-element may have a FAMS tag whose value is @F1@, meaning that this
-element points to the family record in which the associated person
-is a spouse. Likewise, an element with a tag of FAMC has a value
-that points to a family record in which the associated person is a
-child.
-
See a GEDCOM file for examples of tags and their values.
-
Tags available to an element are seen here: gedcom.tags
+
Element associated with a FAM_RECORD
Expand source code
class FamilyElement(Element):
+ """Element associated with a `FAM_RECORD`"""
+
+ def get_tag(self) -> str:
+ return tags.GEDCOM_TAG_FAMILY
+
+ def get_record(self) -> dict:
+ """Parse and return the full record in dictionary format.
+ """
+ record = {
+ 'key_to_family': self.get_pointer(),
+ 'restriction': '',
+ 'events': family_event_structure(self),
+ 'key_to_husband': '',
+ 'key_to_wife': '',
+ 'children': [],
+ 'number_of_children': '',
+ 'submitters': [],
+ 'references': [],
+ 'record_id': '',
+ 'change_date': {},
+ 'notes': [],
+ 'citations': [],
+ 'media': []
+ }
+ lds_events = lds_spouse_sealing(self)
+ if len(lds_events) > 0:
+ for event in lds_events:
+ record['events'].append(event)
- def get_tag(self):
- return gedcom.tags.GEDCOM_TAG_FAMILY
+ for child in self.get_child_elements():
+ if child.get_tag() in FAMILY_SINGLE_TAGS:
+ record[FAMILY_SINGLE_TAGS[child.get_tag()]] = child.get_value()
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_CHILD:
+ entry = {
+ 'key_to_child': child.get_value(),
+ 'relationship_to_father': '',
+ 'relationship_to_mother': ''
+ }
+ for gchild in child.get_child_elements():
+ if gchild.get_tag() == tags.GEDCOM_PROGRAM_DEFINED_TAG_FREL:
+ entry['relationship_to_father'] = gchild.get_value()
+ continue
+
+ if gchild.get_tag() == tags.GEDCOM_PROGRAM_DEFINED_TAG_MREL:
+ entry['relationship_to_mother'] = gchild.get_value()
+
+ record['children'].append(entry)
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_NOTE:
+ record['notes'].append(note_structure(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_SOURCE:
+ record['citations'].append(source_citation(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_OBJECT:
+ record['media'].append(multimedia_link(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_REFERENCE:
+ record['references'].append(user_reference_number(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_CHANGE:
+ record['change_date'] = change_date(child)
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_SUBMITTER:
+ record['submitters'].append(child.get_value())
+ continue
+
+ return record
GEDCOM element for a HEADER header record identified by the
+GEDCOM_TAG_HEADER tag.
+
+
+Expand source code
+
+
# -*- coding: utf-8 -*-
+
+# Python GEDCOM Parser
+#
+# Copyright (C) 2020 Christopher Horn (cdhorn at embarqmail dot com)
+# Copyright (C) 2018 Damon Brodie (damon.brodie at gmail.com)
+# Copyright (C) 2018-2019 Nicklas Reincke (contact at reynke.com)
+# Copyright (C) 2016 Andreas Oberritter
+# Copyright (C) 2012 Madeleine Price Ball
+# Copyright (C) 2005 Daniel Zappala (zappala at cs.byu.edu)
+# Copyright (C) 2005 Brigham Young University
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Further information about the license: http://www.gnu.org/licenses/gpl-2.0.html
+
+"""
+GEDCOM element for a `HEADER` header record identified by the
+`gedcom.tags.GEDCOM_TAG_HEADER` tag.
+"""
+
+import gedcom.tags as tags
+from gedcom.element.element import Element
+from gedcom.subparsers.address_structure import address_structure
+from gedcom.subparsers.note_structure import note_structure
+
+HEADER_TAGS = {
+ tags.GEDCOM_TAG_DESTINATION: 'destination',
+ tags.GEDCOM_TAG_SUBMITTER: 'key_to_submitter',
+ tags.GEDCOM_TAG_SUBMISSION: 'key_to_submission',
+ tags.GEDCOM_TAG_FILE: 'file',
+ tags.GEDCOM_TAG_COPYRIGHT: 'copyright',
+ tags.GEDCOM_TAG_LANGUAGE: 'language',
+ tags.GEDCOM_PROGRAM_DEFINED_TAG_HOME_PERSON: 'key_to_home_person'
+}
+
+
+class HeaderElement(Element):
+ """Element associated with a `HEADER`"""
+
+ def get_tag(self) -> str:
+ return tags.GEDCOM_TAG_HEADER
+
+ def get_record(self) -> dict:
+ """Parse and return the full record in dictionary format.
+ """
+ record = {
+ 'source': '',
+ 'product': {
+ 'version': '',
+ 'name': '',
+ 'corporation': '',
+ 'address': {}
+ },
+ 'data': {
+ 'source_data': '',
+ 'published': '',
+ 'copyright': ''
+ },
+ 'destination': '',
+ 'transmission_date': '',
+ 'transmission_time': '',
+ 'key_to_submitter': '',
+ 'key_to_submission': '',
+ 'file': '',
+ 'copyright': '',
+ 'gedcom': {
+ 'version': '',
+ 'format': '',
+ },
+ 'character_set': '',
+ 'character_set_version': '',
+ 'language': '',
+ 'place_hierarchy': '',
+ 'key_to_home_person': '',
+ 'notes': []
+ }
+ for child in self.get_child_elements():
+ if child.get_tag() == tags.GEDCOM_TAG_SOURCE:
+ record['source'] = child.get_value()
+ for gchild in child.get_child_elements():
+ if gchild.get_tag() == tags.GEDCOM_TAG_VERSION:
+ record['product']['version'] = gchild.get_value()
+ continue
+
+ if gchild.get_tag() == tags.GEDCOM_TAG_NAME:
+ record['product']['name'] = gchild.get_value()
+ continue
+
+ if gchild.get_tag() == tags.GEDCOM_TAG_CORPORATE:
+ record['product']['corporation'] = gchild.get_value()
+
+ for ggchild in gchild.get_child_elements():
+ if ggchild.get_tag() == tags.GEDCOM_TAG_ADDRESS:
+ record['product']['address'] = address_structure(gchild)
+ continue
+
+ if gchild.get_tag() == tags.GEDCOM_TAG_DATA:
+ record['data']['source_data'] = gchild.get_value()
+ for ggchild in gchild.get_child_elements():
+ if ggchild.get_tag() == tags.GEDCOM_TAG_DATE:
+ record['data']['published'] = ggchild.get_value()
+ continue
+
+ if ggchild.get_tag() == tags.GEDCOM_TAG_COPYRIGHT:
+ record['data']['copyright'] = ggchild.get_multi_line_value()
+ continue
+ continue
+
+ if child.get_tag() in HEADER_TAGS:
+ record[HEADER_TAGS[child.get_tag()]] = child.get_value()
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_DATE:
+ record['transmission_date'] = child.get_value()
+ for gchild in child.get_child_elements():
+ if gchild.get_tag() == tags.GEDCOM_TAG_TIME:
+ record['transmission_time'] = gchild.get_value()
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_GEDCOM:
+ for gchild in child.get_child_elements():
+ if gchild.get_tag() == tags.GEDCOM_TAG_VERSION:
+ record['gedcom']['version'] = gchild.get_value()
+ continue
+
+ if gchild.get_tag() == tags.GEDCOM_TAG_FORMAT:
+ record['gedcom']['format'] = gchild.get_value()
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_CHARACTER:
+ record['character_set'] = child.get_value()
+ for gchild in child.get_child_elements():
+ if gchild.get_tag() == tags.GEDCOM_TAG_VERSION:
+ record['character_set_version'] = gchild.get_value()
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_PLACE:
+ for gchild in child.get_child_elements():
+ if gchild.get_tag() == tags.GEDCOM_TAG_FORMAT:
+ record['place_hierarchy'] = gchild.get_value()
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_NOTE:
+ record['notes'].append(note_structure(child))
+
+ return record
GEDCOM element for a INDIVIDUAL_RECORD individual record identified by the
+GEDCOM_TAG_INDIVIDUAL tag.
Expand source code
@@ -29,6 +31,7 @@
Module gedcom.element.individual
# Python GEDCOM Parser
#
+# Copyright (C) 2020 Christopher Horn (cdhorn at embarqmail dot com)
# Copyright (C) 2018 Damon Brodie (damon.brodie at gmail.com)
# Copyright (C) 2018-2019 Nicklas Reincke (contact at reynke.com)
# Copyright (C) 2016 Andreas Oberritter
@@ -52,71 +55,179 @@
Module gedcom.element.individual
#
# Further information about the license: http://www.gnu.org/licenses/gpl-2.0.html
-"""GEDCOM element consisting of tag `gedcom.tags.GEDCOM_TAG_INDIVIDUAL`"""
+"""
+GEDCOM element for a `INDIVIDUAL_RECORD` individual record identified by the
+`gedcom.tags.GEDCOM_TAG_INDIVIDUAL` tag.
+"""
+from typing import Tuple, List
import re as regex
+
+import gedcom.tags as tags
from gedcom.element.element import Element
+from gedcom.subparsers.personal_name_structure import personal_name_structure
+from gedcom.subparsers.individual_event_structure import individual_event_structure
+from gedcom.subparsers.individual_attribute_structure import individual_attribute_structure
+from gedcom.subparsers.lds_individual_ordinance import lds_individual_ordinance
+from gedcom.subparsers.child_to_family_link import child_to_family_link
+from gedcom.subparsers.spouse_to_family_link import spouse_to_family_link
+from gedcom.subparsers.association_structure import association_structure
+from gedcom.subparsers.user_reference_number import user_reference_number
+from gedcom.subparsers.change_date import change_date
+from gedcom.subparsers.note_structure import note_structure
+from gedcom.subparsers.source_citation import source_citation
+from gedcom.subparsers.multimedia_link import multimedia_link
from gedcom.helpers import deprecated
-import gedcom.tags
-
-class NotAnActualIndividualError(Exception):
- pass
+INDIVIDUAL_SINGLE_TAGS = {
+ tags.GEDCOM_TAG_RESTRICTION: 'restriction',
+ tags.GEDCOM_TAG_SEX: 'sex',
+ tags.GEDCOM_TAG_REC_ID_NUMBER: 'record_id',
+ tags.GEDCOM_TAG_REC_FILE_NUMBER: 'permanent_file_number',
+ tags.GEDCOM_TAG_AFN: 'ancestral_file_number'
+}
class IndividualElement(Element):
+ """Element associated with an `INDIVIDUAL_RECORD`"""
+
+ def get_tag(self) -> str:
+ return tags.GEDCOM_TAG_INDIVIDUAL
+
+ def get_record(self) -> dict:
+ """Parse and return the full record in dictionary format.
+ """
+ record = {
+ 'key_to_individual': self.get_pointer(),
+ 'restriction': '',
+ 'names': [],
+ 'sex': 'U',
+ 'events': individual_event_structure(self),
+ 'attributes': individual_attribute_structure(self),
+ 'child_to_family': [],
+ 'spouse_to_family': [],
+ 'submitters': [],
+ 'associates': [],
+ 'aliases': [],
+ 'ancestors_interest': [],
+ 'descendants_interest': [],
+ 'permanent_file_number': '',
+ 'ancestral_file_number': '',
+ 'references': [],
+ 'record_id': '',
+ 'change_date': {},
+ 'notes': [],
+ 'citations': [],
+ 'media': []
+ }
+ lds_events = lds_individual_ordinance(self)
+ if len(lds_events) > 0:
+ for event in lds_events:
+ record['events'].append(event)
+
+ for child in self.get_child_elements():
+ if child.get_tag() in INDIVIDUAL_SINGLE_TAGS:
+ record[INDIVIDUAL_SINGLE_TAGS[child.get_tag()]] = child.get_value()
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_NAME:
+ record['names'].append(personal_name_structure(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_FAMILY_CHILD:
+ record['child_to_family'].append(child_to_family_link(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_FAMILY_SPOUSE:
+ record['spouse_to_family'].append(spouse_to_family_link(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_NOTE:
+ record['notes'].append(note_structure(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_SOURCE:
+ record['citations'].append(source_citation(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_MEDIA:
+ record['media'].append(multimedia_link(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_SUBMITTER:
+ record['submitters'].append(child.get_value())
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_ASSOCIATES:
+ record['associates'].append(association_structure(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_ALIAS:
+ record['aliases'].append(child.get_value())
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_ANCES_INTEREST:
+ record['ancestors_interest'].append(child.get_value())
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_DESCENDANTS_INT:
+ record['descendants_interest'].append(child.get_value())
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_REFERENCE:
+ record['references'].append(user_reference_number(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_CHANGE:
+ record['changed'] = change_date(child)
- def get_tag(self):
- return gedcom.tags.GEDCOM_TAG_INDIVIDUAL
+ return record
- def is_deceased(self):
- """Checks if this individual is deceased
- :rtype: bool
+ def is_deceased(self) -> bool:
+ """Checks if this individual is deceased.
"""
for child in self.get_child_elements():
- if child.get_tag() == gedcom.tags.GEDCOM_TAG_DEATH:
+ if child.get_tag() == tags.GEDCOM_TAG_DEATH:
return True
return False
- def is_child(self):
- """Checks if this element is a child of a family
- :rtype: bool
+ def is_child(self) -> bool:
+ """Checks if this element is a child of a family.
"""
found_child = False
for child in self.get_child_elements():
- if child.get_tag() == gedcom.tags.GEDCOM_TAG_FAMILY_CHILD:
+ if child.get_tag() == tags.GEDCOM_TAG_FAMILY_CHILD:
found_child = True
return found_child
- def is_private(self):
- """Checks if this individual is marked private
- :rtype: bool
+ def is_private(self) -> bool:
+ """Checks if this individual is marked private.
"""
for child in self.get_child_elements():
- if child.get_tag() == gedcom.tags.GEDCOM_TAG_PRIVATE:
+ if child.get_tag() == tags.GEDCOM_TAG_PRIVATE:
private = child.get_value()
if private == 'Y':
return True
return False
- def get_name(self):
+ def get_name(self) -> Tuple[str, str]:
"""Returns an individual's names as a tuple: (`str` given_name, `str` surname)
- :rtype: tuple
"""
given_name = ""
surname = ""
- # Return the first gedcom.tags.GEDCOM_TAG_NAME that is found.
- # Alternatively as soon as we have both the gedcom.tags.GEDCOM_TAG_GIVEN_NAME and _SURNAME return those.
+ # Return the first tags.GEDCOM_TAG_NAME that is found.
+ # Alternatively as soon as we have both the tags.GEDCOM_TAG_GIVEN_NAME
+ # and _SURNAME return those.
found_given_name = False
found_surname_name = False
for child in self.get_child_elements():
- if child.get_tag() == gedcom.tags.GEDCOM_TAG_NAME:
+ if child.get_tag() == tags.GEDCOM_TAG_NAME:
# Some GEDCOM files don't use child tags but instead
# place the name in the value of the NAME tag.
if child.get_value() != "":
@@ -129,14 +240,14 @@
Module gedcom.element.individual
return given_name, surname
- for childOfChild in child.get_child_elements():
+ for gchild in child.get_child_elements():
- if childOfChild.get_tag() == gedcom.tags.GEDCOM_TAG_GIVEN_NAME:
- given_name = childOfChild.get_value()
+ if gchild.get_tag() == tags.GEDCOM_TAG_GIVEN_NAME:
+ given_name = gchild.get_value()
found_given_name = True
- if childOfChild.get_tag() == gedcom.tags.GEDCOM_TAG_SURNAME:
- surname = childOfChild.get_value()
+ if gchild.get_tag() == tags.GEDCOM_TAG_SURNAME:
+ surname = gchild.get_value()
found_surname_name = True
if found_given_name and found_surname_name:
@@ -145,80 +256,74 @@
Module gedcom.element.individual
# If we reach here we are probably returning empty strings
return given_name, surname
- def get_all_names(self):
- return [a.get_value() for a in self.get_child_elements() if a.get_tag() == gedcom.tags.GEDCOM_TAG_NAME]
+ def get_all_names(self) -> List[str]:
+ """Return all names."""
+ return [a.get_value() for a in self.get_child_elements()
+ if a.get_tag() == tags.GEDCOM_TAG_NAME]
- def surname_match(self, surname_to_match):
- """Matches a string with the surname of an individual
- :type surname_to_match: str
- :rtype: bool
+ def surname_match(self, surname_to_match: str) -> bool:
+ """Matches a string with the surname of an individual.
"""
(given_name, surname) = self.get_name()
return regex.search(surname_to_match, surname, regex.IGNORECASE)
@deprecated
- def given_match(self, name):
- """Matches a string with the given name of an individual
+ def given_match(self, name: str) -> bool:
+ """Matches a string with the given name of an individual.
::deprecated:: As of version 1.0.0 use `given_name_match()` method instead
- :type name: str
- :rtype: bool
"""
return self.given_name_match(name)
- def given_name_match(self, given_name_to_match):
- """Matches a string with the given name of an individual
- :type given_name_to_match: str
- :rtype: bool
+ def given_name_match(self, given_name_to_match: str) -> bool:
+ """Matches a string with the given name of an individual.
"""
(given_name, surname) = self.get_name()
return regex.search(given_name_to_match, given_name, regex.IGNORECASE)
- def get_gender(self):
- """Returns the gender of a person in string format
- :rtype: str
+ def get_gender(self) -> str:
+ """Returns the gender of a person in string format.
"""
gender = ""
for child in self.get_child_elements():
- if child.get_tag() == gedcom.tags.GEDCOM_TAG_SEX:
+ if child.get_tag() == tags.GEDCOM_TAG_SEX:
gender = child.get_value()
return gender
- def get_birth_data(self):
- """Returns the birth data of a person formatted as a tuple: (`str` date, `str` place, `list` sources)
- :rtype: tuple
+ def get_birth_data(self) -> Tuple[str, str, List[str]]:
+ """Returns the birth data of a person formatted as a tuple:
+ (`str` date, `str` place, `list` sources)
"""
date = ""
place = ""
sources = []
for child in self.get_child_elements():
- if child.get_tag() == gedcom.tags.GEDCOM_TAG_BIRTH:
- for childOfChild in child.get_child_elements():
+ if child.get_tag() == tags.GEDCOM_TAG_BIRTH:
+ for gchild in child.get_child_elements():
- if childOfChild.get_tag() == gedcom.tags.GEDCOM_TAG_DATE:
- date = childOfChild.get_value()
+ if gchild.get_tag() == tags.GEDCOM_TAG_DATE:
+ date = gchild.get_value()
- if childOfChild.get_tag() == gedcom.tags.GEDCOM_TAG_PLACE:
- place = childOfChild.get_value()
+ if gchild.get_tag() == tags.GEDCOM_TAG_PLACE:
+ place = gchild.get_value()
- if childOfChild.get_tag() == gedcom.tags.GEDCOM_TAG_SOURCE:
- sources.append(childOfChild.get_value())
+ if gchild.get_tag() == tags.GEDCOM_TAG_SOURCE:
+ sources.append(gchild.get_value())
return date, place, sources
- def get_birth_year(self):
- """Returns the birth year of a person in integer format
- :rtype: int
+ def get_birth_year(self) -> int:
+ """Returns the birth year of a person in integer format.
"""
date = ""
for child in self.get_child_elements():
- if child.get_tag() == gedcom.tags.GEDCOM_TAG_BIRTH:
- for childOfChild in child.get_child_elements():
- if childOfChild.get_tag() == gedcom.tags.GEDCOM_TAG_DATE:
- date_split = childOfChild.get_value().split()
+ if child.get_tag() == tags.GEDCOM_TAG_BIRTH:
+ for gchild in child.get_child_elements():
+ if gchild.get_tag() == tags.GEDCOM_TAG_DATE:
+ date_split = gchild.get_value().split()
date = date_split[len(date_split) - 1]
if date == "":
@@ -228,37 +333,36 @@
Module gedcom.element.individual
except ValueError:
return -1
- def get_death_data(self):
- """Returns the death data of a person formatted as a tuple: (`str` date, `str` place, `list` sources)
- :rtype: tuple
+ def get_death_data(self) -> Tuple[str, str, List[str]]:
+ """Returns the death data of a person formatted as a tuple:
+ (`str` date, `str` place, `list` sources)
"""
date = ""
place = ""
sources = []
for child in self.get_child_elements():
- if child.get_tag() == gedcom.tags.GEDCOM_TAG_DEATH:
- for childOfChild in child.get_child_elements():
- if childOfChild.get_tag() == gedcom.tags.GEDCOM_TAG_DATE:
- date = childOfChild.get_value()
- if childOfChild.get_tag() == gedcom.tags.GEDCOM_TAG_PLACE:
- place = childOfChild.get_value()
- if childOfChild.get_tag() == gedcom.tags.GEDCOM_TAG_SOURCE:
- sources.append(childOfChild.get_value())
+ if child.get_tag() == tags.GEDCOM_TAG_DEATH:
+ for gchild in child.get_child_elements():
+ if gchild.get_tag() == tags.GEDCOM_TAG_DATE:
+ date = gchild.get_value()
+ if gchild.get_tag() == tags.GEDCOM_TAG_PLACE:
+ place = gchild.get_value()
+ if gchild.get_tag() == tags.GEDCOM_TAG_SOURCE:
+ sources.append(gchild.get_value())
return date, place, sources
- def get_death_year(self):
- """Returns the death year of a person in integer format
- :rtype: int
+ def get_death_year(self) -> int:
+ """Returns the death year of a person in integer format.
"""
date = ""
for child in self.get_child_elements():
- if child.get_tag() == gedcom.tags.GEDCOM_TAG_DEATH:
- for childOfChild in child.get_child_elements():
- if childOfChild.get_tag() == gedcom.tags.GEDCOM_TAG_DATE:
- date_split = childOfChild.get_value().split()
+ if child.get_tag() == tags.GEDCOM_TAG_DEATH:
+ for gchild in child.get_child_elements():
+ if gchild.get_tag() == tags.GEDCOM_TAG_DATE:
+ date_split = gchild.get_value().split()
date = date_split[len(date_split) - 1]
if date == "":
@@ -269,110 +373,103 @@
Module gedcom.element.individual
return -1
@deprecated
- def get_burial(self):
- """Returns the burial data of a person formatted as a tuple: (`str` date, `str´ place, `list` sources)
+ def get_burial(self) -> Tuple[str, str, List[str]]:
+ """Returns the burial data of a person formatted as a tuple:
+ (`str` date, `str´ place, `list` sources)
::deprecated:: As of version 1.0.0 use `get_burial_data()` method instead
- :rtype: tuple
"""
self.get_burial_data()
- def get_burial_data(self):
- """Returns the burial data of a person formatted as a tuple: (`str` date, `str´ place, `list` sources)
- :rtype: tuple
+ def get_burial_data(self) -> Tuple[str, str, List[str]]:
+ """Returns the burial data of a person formatted as a tuple:
+ (`str` date, `str´ place, `list` sources)
"""
date = ""
place = ""
sources = []
for child in self.get_child_elements():
- if child.get_tag() == gedcom.tags.GEDCOM_TAG_BURIAL:
- for childOfChild in child.get_child_elements():
+ if child.get_tag() == tags.GEDCOM_TAG_BURIAL:
+ for gchild in child.get_child_elements():
- if childOfChild.get_tag() == gedcom.tags.GEDCOM_TAG_DATE:
- date = childOfChild.get_value()
+ if gchild.get_tag() == tags.GEDCOM_TAG_DATE:
+ date = gchild.get_value()
- if childOfChild.get_tag() == gedcom.tags.GEDCOM_TAG_PLACE:
- place = childOfChild.get_value()
+ if gchild.get_tag() == tags.GEDCOM_TAG_PLACE:
+ place = gchild.get_value()
- if childOfChild.get_tag() == gedcom.tags.GEDCOM_TAG_SOURCE:
- sources.append(childOfChild.get_value())
+ if gchild.get_tag() == tags.GEDCOM_TAG_SOURCE:
+ sources.append(gchild.get_value())
return date, place, sources
@deprecated
- def get_census(self):
- """Returns a list of censuses of an individual formatted as tuples: (`str` date, `str´ place, `list` sources)
+ def get_census(self) -> List[Tuple[str, str, List[str]]]:
+ """Returns a list of censuses of an individual formatted as tuples:
+ (`str` date, `str´ place, `list` sources)
::deprecated:: As of version 1.0.0 use `get_census_data()` method instead
- :rtype: list of tuple
"""
self.get_census_data()
- def get_census_data(self):
- """Returns a list of censuses of an individual formatted as tuples: (`str` date, `str´ place, `list` sources)
- :rtype: list of tuple
+ def get_census_data(self) -> List[Tuple[str, str, List[str]]]:
+ """Returns a list of censuses of an individual formatted as tuples:
+ (`str` date, `str´ place, `list` sources)
"""
census = []
for child in self.get_child_elements():
- if child.get_tag() == gedcom.tags.GEDCOM_TAG_CENSUS:
+ if child.get_tag() == tags.GEDCOM_TAG_CENSUS:
date = ''
place = ''
sources = []
- for childOfChild in child.get_child_elements():
+ for gchild in child.get_child_elements():
- if childOfChild.get_tag() == gedcom.tags.GEDCOM_TAG_DATE:
- date = childOfChild.get_value()
+ if gchild.get_tag() == tags.GEDCOM_TAG_DATE:
+ date = gchild.get_value()
- if childOfChild.get_tag() == gedcom.tags.GEDCOM_TAG_PLACE:
- place = childOfChild.get_value()
+ if gchild.get_tag() == tags.GEDCOM_TAG_PLACE:
+ place = gchild.get_value()
- if childOfChild.get_tag() == gedcom.tags.GEDCOM_TAG_SOURCE:
- sources.append(childOfChild.get_value())
+ if gchild.get_tag() == tags.GEDCOM_TAG_SOURCE:
+ sources.append(gchild.get_value())
census.append((date, place, sources))
return census
- def get_last_change_date(self):
- """Returns the date of when the person data was last changed formatted as a string
- :rtype: str
+ def get_last_change_date(self) -> str:
+ """Returns the date of when the person data was last changed formatted as a string.
"""
date = ""
for child in self.get_child_elements():
- if child.get_tag() == gedcom.tags.GEDCOM_TAG_CHANGE:
- for childOfChild in child.get_child_elements():
- if childOfChild.get_tag() == gedcom.tags.GEDCOM_TAG_DATE:
- date = childOfChild.get_value()
+ if child.get_tag() == tags.GEDCOM_TAG_CHANGE:
+ for gchild in child.get_child_elements():
+ if gchild.get_tag() == tags.GEDCOM_TAG_DATE:
+ date = gchild.get_value()
return date
- def get_occupation(self):
- """Returns the occupation of a person
- :rtype: str
+ def get_occupation(self) -> str:
+ """Returns the occupation of a person.
"""
occupation = ""
for child in self.get_child_elements():
- if child.get_tag() == gedcom.tags.GEDCOM_TAG_OCCUPATION:
+ if child.get_tag() == tags.GEDCOM_TAG_OCCUPATION:
occupation = child.get_value()
return occupation
- def birth_year_match(self, year):
- """Returns `True` if the given year matches the birth year of this person
- :type year: int
- :rtype: bool
+ def birth_year_match(self, year: int) -> bool:
+ """Returns `True` if the given year matches the birth year of this person.
"""
return self.get_birth_year() == year
- def birth_range_match(self, from_year, to_year):
- """Checks if the birth year of a person lies within the given range
- :type from_year: int
- :type to_year: int
- :rtype: bool
+ def birth_range_match(self, from_year: int, to_year: int) -> bool:
+ """Checks if the birth year of a person lies within the given range.
"""
birth_year = self.get_birth_year()
@@ -381,18 +478,13 @@
Module gedcom.element.individual
return False
- def death_year_match(self, year):
- """Returns `True` if the given year matches the death year of this person
- :type year: int
- :rtype: bool
+ def death_year_match(self, year: int) -> bool:
+ """Returns `True` if the given year matches the death year of this person.
"""
return self.get_death_year() == year
- def death_range_match(self, from_year, to_year):
- """Checks if the death year of a person lies within the given range
- :type from_year: int
- :type to_year: int
- :rtype: bool
+ def death_range_match(self, from_year: int, to_year: int) -> bool:
+ """Checks if the death year of a person lies within the given range.
"""
death_year = self.get_death_year()
@@ -401,8 +493,8 @@
Module gedcom.element.individual
return False
- def criteria_match(self, criteria):
- """Checks if this individual matches all of the given criteria
+ def criteria_match(self, criteria: str) -> bool:
+ """Checks if this individual matches all of the given criteria.
`criteria` is a colon-separated list, where each item in the
list has the form [name]=[value]. The following criteria are supported:
@@ -416,9 +508,6 @@
Module gedcom.element.individual
birth_range=[from_year-to_year]
Match a person whose birth year is in the range of years from
[from_year] to [to_year], including both [from_year] and [to_year].
-
- :type criteria: str
- :rtype: bool
"""
# Check if criteria is a valid criteria and can be split by `:` and `=` characters
@@ -491,87 +580,154 @@
Each line in a GEDCOM file is an element with the format
-
level [pointer] tag [value]
-
where level and tag are required, and pointer and value are
-optional.
-Elements are arranged hierarchically according to their
-level, and elements with a level of zero are at the top level.
-Elements with a level greater than zero are children of their
-parent.
-
A pointer has the format @pname@, where pname is any sequence of
-characters and numbers. The pointer identifies the object being
-pointed to, so that any pointer included as the value of any
-element points back to the original object.
-For example, an
-element may have a FAMS tag whose value is @F1@, meaning that this
-element points to the family record in which the associated person
-is a spouse. Likewise, an element with a tag of FAMC has a value
-that points to a family record in which the associated person is a
-child.
-
See a GEDCOM file for examples of tags and their values.
-
Tags available to an element are seen here: gedcom.tags
+
Element associated with an INDIVIDUAL_RECORD
Expand source code
class IndividualElement(Element):
+ """Element associated with an `INDIVIDUAL_RECORD`"""
+
+ def get_tag(self) -> str:
+ return tags.GEDCOM_TAG_INDIVIDUAL
+
+ def get_record(self) -> dict:
+ """Parse and return the full record in dictionary format.
+ """
+ record = {
+ 'key_to_individual': self.get_pointer(),
+ 'restriction': '',
+ 'names': [],
+ 'sex': 'U',
+ 'events': individual_event_structure(self),
+ 'attributes': individual_attribute_structure(self),
+ 'child_to_family': [],
+ 'spouse_to_family': [],
+ 'submitters': [],
+ 'associates': [],
+ 'aliases': [],
+ 'ancestors_interest': [],
+ 'descendants_interest': [],
+ 'permanent_file_number': '',
+ 'ancestral_file_number': '',
+ 'references': [],
+ 'record_id': '',
+ 'change_date': {},
+ 'notes': [],
+ 'citations': [],
+ 'media': []
+ }
+ lds_events = lds_individual_ordinance(self)
+ if len(lds_events) > 0:
+ for event in lds_events:
+ record['events'].append(event)
+
+ for child in self.get_child_elements():
+ if child.get_tag() in INDIVIDUAL_SINGLE_TAGS:
+ record[INDIVIDUAL_SINGLE_TAGS[child.get_tag()]] = child.get_value()
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_NAME:
+ record['names'].append(personal_name_structure(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_FAMILY_CHILD:
+ record['child_to_family'].append(child_to_family_link(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_FAMILY_SPOUSE:
+ record['spouse_to_family'].append(spouse_to_family_link(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_NOTE:
+ record['notes'].append(note_structure(child))
+ continue
- def get_tag(self):
- return gedcom.tags.GEDCOM_TAG_INDIVIDUAL
+ if child.get_tag() == tags.GEDCOM_TAG_SOURCE:
+ record['citations'].append(source_citation(child))
+ continue
- def is_deceased(self):
- """Checks if this individual is deceased
- :rtype: bool
+ if child.get_tag() == tags.GEDCOM_TAG_MEDIA:
+ record['media'].append(multimedia_link(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_SUBMITTER:
+ record['submitters'].append(child.get_value())
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_ASSOCIATES:
+ record['associates'].append(association_structure(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_ALIAS:
+ record['aliases'].append(child.get_value())
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_ANCES_INTEREST:
+ record['ancestors_interest'].append(child.get_value())
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_DESCENDANTS_INT:
+ record['descendants_interest'].append(child.get_value())
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_REFERENCE:
+ record['references'].append(user_reference_number(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_CHANGE:
+ record['changed'] = change_date(child)
+
+ return record
+
+ def is_deceased(self) -> bool:
+ """Checks if this individual is deceased.
"""
for child in self.get_child_elements():
- if child.get_tag() == gedcom.tags.GEDCOM_TAG_DEATH:
+ if child.get_tag() == tags.GEDCOM_TAG_DEATH:
return True
return False
- def is_child(self):
- """Checks if this element is a child of a family
- :rtype: bool
+ def is_child(self) -> bool:
+ """Checks if this element is a child of a family.
"""
found_child = False
for child in self.get_child_elements():
- if child.get_tag() == gedcom.tags.GEDCOM_TAG_FAMILY_CHILD:
+ if child.get_tag() == tags.GEDCOM_TAG_FAMILY_CHILD:
found_child = True
return found_child
- def is_private(self):
- """Checks if this individual is marked private
- :rtype: bool
+ def is_private(self) -> bool:
+ """Checks if this individual is marked private.
"""
for child in self.get_child_elements():
- if child.get_tag() == gedcom.tags.GEDCOM_TAG_PRIVATE:
+ if child.get_tag() == tags.GEDCOM_TAG_PRIVATE:
private = child.get_value()
if private == 'Y':
return True
return False
- def get_name(self):
+ def get_name(self) -> Tuple[str, str]:
"""Returns an individual's names as a tuple: (`str` given_name, `str` surname)
- :rtype: tuple
"""
given_name = ""
surname = ""
- # Return the first gedcom.tags.GEDCOM_TAG_NAME that is found.
- # Alternatively as soon as we have both the gedcom.tags.GEDCOM_TAG_GIVEN_NAME and _SURNAME return those.
+ # Return the first tags.GEDCOM_TAG_NAME that is found.
+ # Alternatively as soon as we have both the tags.GEDCOM_TAG_GIVEN_NAME
+ # and _SURNAME return those.
found_given_name = False
found_surname_name = False
for child in self.get_child_elements():
- if child.get_tag() == gedcom.tags.GEDCOM_TAG_NAME:
+ if child.get_tag() == tags.GEDCOM_TAG_NAME:
# Some GEDCOM files don't use child tags but instead
# place the name in the value of the NAME tag.
if child.get_value() != "":
@@ -584,14 +740,14 @@
Classes
return given_name, surname
- for childOfChild in child.get_child_elements():
+ for gchild in child.get_child_elements():
- if childOfChild.get_tag() == gedcom.tags.GEDCOM_TAG_GIVEN_NAME:
- given_name = childOfChild.get_value()
+ if gchild.get_tag() == tags.GEDCOM_TAG_GIVEN_NAME:
+ given_name = gchild.get_value()
found_given_name = True
- if childOfChild.get_tag() == gedcom.tags.GEDCOM_TAG_SURNAME:
- surname = childOfChild.get_value()
+ if gchild.get_tag() == tags.GEDCOM_TAG_SURNAME:
+ surname = gchild.get_value()
found_surname_name = True
if found_given_name and found_surname_name:
@@ -600,80 +756,74 @@
Classes
# If we reach here we are probably returning empty strings
return given_name, surname
- def get_all_names(self):
- return [a.get_value() for a in self.get_child_elements() if a.get_tag() == gedcom.tags.GEDCOM_TAG_NAME]
+ def get_all_names(self) -> List[str]:
+ """Return all names."""
+ return [a.get_value() for a in self.get_child_elements()
+ if a.get_tag() == tags.GEDCOM_TAG_NAME]
- def surname_match(self, surname_to_match):
- """Matches a string with the surname of an individual
- :type surname_to_match: str
- :rtype: bool
+ def surname_match(self, surname_to_match: str) -> bool:
+ """Matches a string with the surname of an individual.
"""
(given_name, surname) = self.get_name()
return regex.search(surname_to_match, surname, regex.IGNORECASE)
@deprecated
- def given_match(self, name):
- """Matches a string with the given name of an individual
+ def given_match(self, name: str) -> bool:
+ """Matches a string with the given name of an individual.
::deprecated:: As of version 1.0.0 use `given_name_match()` method instead
- :type name: str
- :rtype: bool
"""
return self.given_name_match(name)
- def given_name_match(self, given_name_to_match):
- """Matches a string with the given name of an individual
- :type given_name_to_match: str
- :rtype: bool
+ def given_name_match(self, given_name_to_match: str) -> bool:
+ """Matches a string with the given name of an individual.
"""
(given_name, surname) = self.get_name()
return regex.search(given_name_to_match, given_name, regex.IGNORECASE)
- def get_gender(self):
- """Returns the gender of a person in string format
- :rtype: str
+ def get_gender(self) -> str:
+ """Returns the gender of a person in string format.
"""
gender = ""
for child in self.get_child_elements():
- if child.get_tag() == gedcom.tags.GEDCOM_TAG_SEX:
+ if child.get_tag() == tags.GEDCOM_TAG_SEX:
gender = child.get_value()
return gender
- def get_birth_data(self):
- """Returns the birth data of a person formatted as a tuple: (`str` date, `str` place, `list` sources)
- :rtype: tuple
+ def get_birth_data(self) -> Tuple[str, str, List[str]]:
+ """Returns the birth data of a person formatted as a tuple:
+ (`str` date, `str` place, `list` sources)
"""
date = ""
place = ""
sources = []
for child in self.get_child_elements():
- if child.get_tag() == gedcom.tags.GEDCOM_TAG_BIRTH:
- for childOfChild in child.get_child_elements():
+ if child.get_tag() == tags.GEDCOM_TAG_BIRTH:
+ for gchild in child.get_child_elements():
- if childOfChild.get_tag() == gedcom.tags.GEDCOM_TAG_DATE:
- date = childOfChild.get_value()
+ if gchild.get_tag() == tags.GEDCOM_TAG_DATE:
+ date = gchild.get_value()
- if childOfChild.get_tag() == gedcom.tags.GEDCOM_TAG_PLACE:
- place = childOfChild.get_value()
+ if gchild.get_tag() == tags.GEDCOM_TAG_PLACE:
+ place = gchild.get_value()
- if childOfChild.get_tag() == gedcom.tags.GEDCOM_TAG_SOURCE:
- sources.append(childOfChild.get_value())
+ if gchild.get_tag() == tags.GEDCOM_TAG_SOURCE:
+ sources.append(gchild.get_value())
return date, place, sources
- def get_birth_year(self):
- """Returns the birth year of a person in integer format
- :rtype: int
+ def get_birth_year(self) -> int:
+ """Returns the birth year of a person in integer format.
"""
date = ""
for child in self.get_child_elements():
- if child.get_tag() == gedcom.tags.GEDCOM_TAG_BIRTH:
- for childOfChild in child.get_child_elements():
- if childOfChild.get_tag() == gedcom.tags.GEDCOM_TAG_DATE:
- date_split = childOfChild.get_value().split()
+ if child.get_tag() == tags.GEDCOM_TAG_BIRTH:
+ for gchild in child.get_child_elements():
+ if gchild.get_tag() == tags.GEDCOM_TAG_DATE:
+ date_split = gchild.get_value().split()
date = date_split[len(date_split) - 1]
if date == "":
@@ -683,37 +833,36 @@
Classes
except ValueError:
return -1
- def get_death_data(self):
- """Returns the death data of a person formatted as a tuple: (`str` date, `str` place, `list` sources)
- :rtype: tuple
+ def get_death_data(self) -> Tuple[str, str, List[str]]:
+ """Returns the death data of a person formatted as a tuple:
+ (`str` date, `str` place, `list` sources)
"""
date = ""
place = ""
sources = []
for child in self.get_child_elements():
- if child.get_tag() == gedcom.tags.GEDCOM_TAG_DEATH:
- for childOfChild in child.get_child_elements():
- if childOfChild.get_tag() == gedcom.tags.GEDCOM_TAG_DATE:
- date = childOfChild.get_value()
- if childOfChild.get_tag() == gedcom.tags.GEDCOM_TAG_PLACE:
- place = childOfChild.get_value()
- if childOfChild.get_tag() == gedcom.tags.GEDCOM_TAG_SOURCE:
- sources.append(childOfChild.get_value())
+ if child.get_tag() == tags.GEDCOM_TAG_DEATH:
+ for gchild in child.get_child_elements():
+ if gchild.get_tag() == tags.GEDCOM_TAG_DATE:
+ date = gchild.get_value()
+ if gchild.get_tag() == tags.GEDCOM_TAG_PLACE:
+ place = gchild.get_value()
+ if gchild.get_tag() == tags.GEDCOM_TAG_SOURCE:
+ sources.append(gchild.get_value())
return date, place, sources
- def get_death_year(self):
- """Returns the death year of a person in integer format
- :rtype: int
+ def get_death_year(self) -> int:
+ """Returns the death year of a person in integer format.
"""
date = ""
for child in self.get_child_elements():
- if child.get_tag() == gedcom.tags.GEDCOM_TAG_DEATH:
- for childOfChild in child.get_child_elements():
- if childOfChild.get_tag() == gedcom.tags.GEDCOM_TAG_DATE:
- date_split = childOfChild.get_value().split()
+ if child.get_tag() == tags.GEDCOM_TAG_DEATH:
+ for gchild in child.get_child_elements():
+ if gchild.get_tag() == tags.GEDCOM_TAG_DATE:
+ date_split = gchild.get_value().split()
date = date_split[len(date_split) - 1]
if date == "":
@@ -724,110 +873,103 @@
Classes
return -1
@deprecated
- def get_burial(self):
- """Returns the burial data of a person formatted as a tuple: (`str` date, `str´ place, `list` sources)
+ def get_burial(self) -> Tuple[str, str, List[str]]:
+ """Returns the burial data of a person formatted as a tuple:
+ (`str` date, `str´ place, `list` sources)
::deprecated:: As of version 1.0.0 use `get_burial_data()` method instead
- :rtype: tuple
"""
self.get_burial_data()
- def get_burial_data(self):
- """Returns the burial data of a person formatted as a tuple: (`str` date, `str´ place, `list` sources)
- :rtype: tuple
+ def get_burial_data(self) -> Tuple[str, str, List[str]]:
+ """Returns the burial data of a person formatted as a tuple:
+ (`str` date, `str´ place, `list` sources)
"""
date = ""
place = ""
sources = []
for child in self.get_child_elements():
- if child.get_tag() == gedcom.tags.GEDCOM_TAG_BURIAL:
- for childOfChild in child.get_child_elements():
+ if child.get_tag() == tags.GEDCOM_TAG_BURIAL:
+ for gchild in child.get_child_elements():
- if childOfChild.get_tag() == gedcom.tags.GEDCOM_TAG_DATE:
- date = childOfChild.get_value()
+ if gchild.get_tag() == tags.GEDCOM_TAG_DATE:
+ date = gchild.get_value()
- if childOfChild.get_tag() == gedcom.tags.GEDCOM_TAG_PLACE:
- place = childOfChild.get_value()
+ if gchild.get_tag() == tags.GEDCOM_TAG_PLACE:
+ place = gchild.get_value()
- if childOfChild.get_tag() == gedcom.tags.GEDCOM_TAG_SOURCE:
- sources.append(childOfChild.get_value())
+ if gchild.get_tag() == tags.GEDCOM_TAG_SOURCE:
+ sources.append(gchild.get_value())
return date, place, sources
@deprecated
- def get_census(self):
- """Returns a list of censuses of an individual formatted as tuples: (`str` date, `str´ place, `list` sources)
+ def get_census(self) -> List[Tuple[str, str, List[str]]]:
+ """Returns a list of censuses of an individual formatted as tuples:
+ (`str` date, `str´ place, `list` sources)
::deprecated:: As of version 1.0.0 use `get_census_data()` method instead
- :rtype: list of tuple
"""
self.get_census_data()
- def get_census_data(self):
- """Returns a list of censuses of an individual formatted as tuples: (`str` date, `str´ place, `list` sources)
- :rtype: list of tuple
+ def get_census_data(self) -> List[Tuple[str, str, List[str]]]:
+ """Returns a list of censuses of an individual formatted as tuples:
+ (`str` date, `str´ place, `list` sources)
"""
census = []
for child in self.get_child_elements():
- if child.get_tag() == gedcom.tags.GEDCOM_TAG_CENSUS:
+ if child.get_tag() == tags.GEDCOM_TAG_CENSUS:
date = ''
place = ''
sources = []
- for childOfChild in child.get_child_elements():
+ for gchild in child.get_child_elements():
- if childOfChild.get_tag() == gedcom.tags.GEDCOM_TAG_DATE:
- date = childOfChild.get_value()
+ if gchild.get_tag() == tags.GEDCOM_TAG_DATE:
+ date = gchild.get_value()
- if childOfChild.get_tag() == gedcom.tags.GEDCOM_TAG_PLACE:
- place = childOfChild.get_value()
+ if gchild.get_tag() == tags.GEDCOM_TAG_PLACE:
+ place = gchild.get_value()
- if childOfChild.get_tag() == gedcom.tags.GEDCOM_TAG_SOURCE:
- sources.append(childOfChild.get_value())
+ if gchild.get_tag() == tags.GEDCOM_TAG_SOURCE:
+ sources.append(gchild.get_value())
census.append((date, place, sources))
return census
- def get_last_change_date(self):
- """Returns the date of when the person data was last changed formatted as a string
- :rtype: str
+ def get_last_change_date(self) -> str:
+ """Returns the date of when the person data was last changed formatted as a string.
"""
date = ""
for child in self.get_child_elements():
- if child.get_tag() == gedcom.tags.GEDCOM_TAG_CHANGE:
- for childOfChild in child.get_child_elements():
- if childOfChild.get_tag() == gedcom.tags.GEDCOM_TAG_DATE:
- date = childOfChild.get_value()
+ if child.get_tag() == tags.GEDCOM_TAG_CHANGE:
+ for gchild in child.get_child_elements():
+ if gchild.get_tag() == tags.GEDCOM_TAG_DATE:
+ date = gchild.get_value()
return date
- def get_occupation(self):
- """Returns the occupation of a person
- :rtype: str
+ def get_occupation(self) -> str:
+ """Returns the occupation of a person.
"""
occupation = ""
for child in self.get_child_elements():
- if child.get_tag() == gedcom.tags.GEDCOM_TAG_OCCUPATION:
+ if child.get_tag() == tags.GEDCOM_TAG_OCCUPATION:
occupation = child.get_value()
return occupation
- def birth_year_match(self, year):
- """Returns `True` if the given year matches the birth year of this person
- :type year: int
- :rtype: bool
+ def birth_year_match(self, year: int) -> bool:
+ """Returns `True` if the given year matches the birth year of this person.
"""
return self.get_birth_year() == year
- def birth_range_match(self, from_year, to_year):
- """Checks if the birth year of a person lies within the given range
- :type from_year: int
- :type to_year: int
- :rtype: bool
+ def birth_range_match(self, from_year: int, to_year: int) -> bool:
+ """Checks if the birth year of a person lies within the given range.
"""
birth_year = self.get_birth_year()
@@ -836,18 +978,13 @@
Classes
return False
- def death_year_match(self, year):
- """Returns `True` if the given year matches the death year of this person
- :type year: int
- :rtype: bool
+ def death_year_match(self, year: int) -> bool:
+ """Returns `True` if the given year matches the death year of this person.
"""
return self.get_death_year() == year
- def death_range_match(self, from_year, to_year):
- """Checks if the death year of a person lies within the given range
- :type from_year: int
- :type to_year: int
- :rtype: bool
+ def death_range_match(self, from_year: int, to_year: int) -> bool:
+ """Checks if the death year of a person lies within the given range.
"""
death_year = self.get_death_year()
@@ -856,8 +993,8 @@
Classes
return False
- def criteria_match(self, criteria):
- """Checks if this individual matches all of the given criteria
+ def criteria_match(self, criteria: str) -> bool:
+ """Checks if this individual matches all of the given criteria.
`criteria` is a colon-separated list, where each item in the
list has the form [name]=[value]. The following criteria are supported:
@@ -871,9 +1008,6 @@
Classes
birth_range=[from_year-to_year]
Match a person whose birth year is in the range of years from
[from_year] to [to_year], including both [from_year] and [to_year].
-
- :type criteria: str
- :rtype: bool
"""
# Check if criteria is a valid criteria and can be split by `:` and `=` characters
@@ -941,22 +1075,16 @@
Checks if the birth year of a person lies within the given range
-:type from_year: int
-:type to_year: int
-:rtype: bool
+
Checks if the birth year of a person lies within the given range.
Expand source code
-
def birth_range_match(self, from_year, to_year):
- """Checks if the birth year of a person lies within the given range
- :type from_year: int
- :type to_year: int
- :rtype: bool
+
def birth_range_match(self, from_year: int, to_year: int) -> bool:
+ """Checks if the birth year of a person lies within the given range.
"""
birth_year = self.get_birth_year()
@@ -967,29 +1095,25 @@
Returns True if the given year matches the birth year of this person
-:type year: int
-:rtype: bool
+
Returns True if the given year matches the birth year of this person.
Expand source code
-
def birth_year_match(self, year):
- """Returns `True` if the given year matches the birth year of this person
- :type year: int
- :rtype: bool
+
def birth_year_match(self, year: int) -> bool:
+ """Returns `True` if the given year matches the birth year of this person.
"""
return self.get_birth_year() == year
Checks if this individual matches all of the given criteria
+
Checks if this individual matches all of the given criteria.
criteria is a colon-separated list, where each item in the
list has the form [name]=[value]. The following criteria are supported:
surname=[name]
@@ -1000,15 +1124,13 @@
Methods
Match a person whose birth year is a four-digit [year].
birth_range=[from_year-to_year]
Match a person whose birth year is in the range of years from
-[from_year] to [to_year], including both [from_year] and [to_year].
-
:type criteria: str
-:rtype: bool
+[from_year] to [to_year], including both [from_year] and [to_year].
Expand source code
-
def criteria_match(self, criteria):
- """Checks if this individual matches all of the given criteria
+
def criteria_match(self, criteria: str) -> bool:
+ """Checks if this individual matches all of the given criteria.
`criteria` is a colon-separated list, where each item in the
list has the form [name]=[value]. The following criteria are supported:
@@ -1022,9 +1144,6 @@
Methods
birth_range=[from_year-to_year]
Match a person whose birth year is in the range of years from
[from_year] to [to_year], including both [from_year] and [to_year].
-
- :type criteria: str
- :rtype: bool
"""
# Check if criteria is a valid criteria and can be split by `:` and `=` characters
@@ -1087,22 +1206,16 @@
Checks if the death year of a person lies within the given range
-:type from_year: int
-:type to_year: int
-:rtype: bool
+
Checks if the death year of a person lies within the given range.
Expand source code
-
def death_range_match(self, from_year, to_year):
- """Checks if the death year of a person lies within the given range
- :type from_year: int
- :type to_year: int
- :rtype: bool
+
def death_range_match(self, from_year: int, to_year: int) -> bool:
+ """Checks if the death year of a person lies within the given range.
"""
death_year = self.get_death_year()
@@ -1113,92 +1226,88 @@
Returns True if the given year matches the death year of this person
-:type year: int
-:rtype: bool
+
Returns True if the given year matches the death year of this person.
Expand source code
-
def death_year_match(self, year):
- """Returns `True` if the given year matches the death year of this person
- :type year: int
- :rtype: bool
+
def death_year_match(self, year: int) -> bool:
+ """Returns `True` if the given year matches the death year of this person.
"""
return self.get_death_year() == year
def get_all_names(self):
- return [a.get_value() for a in self.get_child_elements() if a.get_tag() == gedcom.tags.GEDCOM_TAG_NAME]
+
def get_all_names(self) -> List[str]:
+ """Return all names."""
+ return [a.get_value() for a in self.get_child_elements()
+ if a.get_tag() == tags.GEDCOM_TAG_NAME]
Returns the birth data of a person formatted as a tuple: (str date, str place, list sources)
-:rtype: tuple
+
Returns the birth data of a person formatted as a tuple:
+(str date, str place, list sources)
Expand source code
-
def get_birth_data(self):
- """Returns the birth data of a person formatted as a tuple: (`str` date, `str` place, `list` sources)
- :rtype: tuple
+
def get_birth_data(self) -> Tuple[str, str, List[str]]:
+ """Returns the birth data of a person formatted as a tuple:
+ (`str` date, `str` place, `list` sources)
"""
date = ""
place = ""
sources = []
for child in self.get_child_elements():
- if child.get_tag() == gedcom.tags.GEDCOM_TAG_BIRTH:
- for childOfChild in child.get_child_elements():
+ if child.get_tag() == tags.GEDCOM_TAG_BIRTH:
+ for gchild in child.get_child_elements():
- if childOfChild.get_tag() == gedcom.tags.GEDCOM_TAG_DATE:
- date = childOfChild.get_value()
+ if gchild.get_tag() == tags.GEDCOM_TAG_DATE:
+ date = gchild.get_value()
- if childOfChild.get_tag() == gedcom.tags.GEDCOM_TAG_PLACE:
- place = childOfChild.get_value()
+ if gchild.get_tag() == tags.GEDCOM_TAG_PLACE:
+ place = gchild.get_value()
- if childOfChild.get_tag() == gedcom.tags.GEDCOM_TAG_SOURCE:
- sources.append(childOfChild.get_value())
+ if gchild.get_tag() == tags.GEDCOM_TAG_SOURCE:
+ sources.append(gchild.get_value())
return date, place, sources
-def get_birth_year(self)
+def get_birth_year(self) -> int
-
Returns the birth year of a person in integer format
-:rtype: int
+
Returns the birth year of a person in integer format.
Expand source code
-
def get_birth_year(self):
- """Returns the birth year of a person in integer format
- :rtype: int
+
def get_birth_year(self) -> int:
+ """Returns the birth year of a person in integer format.
"""
date = ""
for child in self.get_child_elements():
- if child.get_tag() == gedcom.tags.GEDCOM_TAG_BIRTH:
- for childOfChild in child.get_child_elements():
- if childOfChild.get_tag() == gedcom.tags.GEDCOM_TAG_DATE:
- date_split = childOfChild.get_value().split()
+ if child.get_tag() == tags.GEDCOM_TAG_BIRTH:
+ for gchild in child.get_child_elements():
+ if gchild.get_tag() == tags.GEDCOM_TAG_DATE:
+ date_split = gchild.get_value().split()
date = date_split[len(date_split) - 1]
if date == "":
@@ -1210,112 +1319,112 @@
Returns the burial data of a person formatted as a tuple: (str date, str´ place,listsources)
-::deprecated:: As of version 1.0.0 useget_burial_data()` method instead
-:rtype: tuple
+
Returns the burial data of a person formatted as a tuple:
+(str date, str´ place,list` sources)
+::deprecated:: As of version 1.0.0 use get_burial_data() method instead
Expand source code
@deprecated
-def get_burial(self):
- """Returns the burial data of a person formatted as a tuple: (`str` date, `str´ place, `list` sources)
+def get_burial(self) -> Tuple[str, str, List[str]]:
+ """Returns the burial data of a person formatted as a tuple:
+ (`str` date, `str´ place, `list` sources)
::deprecated:: As of version 1.0.0 use `get_burial_data()` method instead
- :rtype: tuple
"""
self.get_burial_data()
Returns the burial data of a person formatted as a tuple: (str date, str´ place,list` sources)
-:rtype: tuple
+
Returns the burial data of a person formatted as a tuple:
+(str date, str´ place,list` sources)
Expand source code
-
def get_burial_data(self):
- """Returns the burial data of a person formatted as a tuple: (`str` date, `str´ place, `list` sources)
- :rtype: tuple
+
def get_burial_data(self) -> Tuple[str, str, List[str]]:
+ """Returns the burial data of a person formatted as a tuple:
+ (`str` date, `str´ place, `list` sources)
"""
date = ""
place = ""
sources = []
for child in self.get_child_elements():
- if child.get_tag() == gedcom.tags.GEDCOM_TAG_BURIAL:
- for childOfChild in child.get_child_elements():
+ if child.get_tag() == tags.GEDCOM_TAG_BURIAL:
+ for gchild in child.get_child_elements():
- if childOfChild.get_tag() == gedcom.tags.GEDCOM_TAG_DATE:
- date = childOfChild.get_value()
+ if gchild.get_tag() == tags.GEDCOM_TAG_DATE:
+ date = gchild.get_value()
- if childOfChild.get_tag() == gedcom.tags.GEDCOM_TAG_PLACE:
- place = childOfChild.get_value()
+ if gchild.get_tag() == tags.GEDCOM_TAG_PLACE:
+ place = gchild.get_value()
- if childOfChild.get_tag() == gedcom.tags.GEDCOM_TAG_SOURCE:
- sources.append(childOfChild.get_value())
+ if gchild.get_tag() == tags.GEDCOM_TAG_SOURCE:
+ sources.append(gchild.get_value())
return date, place, sources
Returns a list of censuses of an individual formatted as tuples: (str date, str´ place,listsources)
-::deprecated:: As of version 1.0.0 useget_census_data()` method instead
-:rtype: list of tuple
+
Returns a list of censuses of an individual formatted as tuples:
+(str date, str´ place,list` sources)
+::deprecated:: As of version 1.0.0 use get_census_data() method instead
Expand source code
@deprecated
-def get_census(self):
- """Returns a list of censuses of an individual formatted as tuples: (`str` date, `str´ place, `list` sources)
+def get_census(self) -> List[Tuple[str, str, List[str]]]:
+ """Returns a list of censuses of an individual formatted as tuples:
+ (`str` date, `str´ place, `list` sources)
::deprecated:: As of version 1.0.0 use `get_census_data()` method instead
- :rtype: list of tuple
"""
self.get_census_data()
Returns a list of censuses of an individual formatted as tuples: (str date, str´ place,list` sources)
-:rtype: list of tuple
+
Returns a list of censuses of an individual formatted as tuples:
+(str date, str´ place,list` sources)
Expand source code
-
def get_census_data(self):
- """Returns a list of censuses of an individual formatted as tuples: (`str` date, `str´ place, `list` sources)
- :rtype: list of tuple
+
def get_census_data(self) -> List[Tuple[str, str, List[str]]]:
+ """Returns a list of censuses of an individual formatted as tuples:
+ (`str` date, `str´ place, `list` sources)
"""
census = []
for child in self.get_child_elements():
- if child.get_tag() == gedcom.tags.GEDCOM_TAG_CENSUS:
+ if child.get_tag() == tags.GEDCOM_TAG_CENSUS:
date = ''
place = ''
sources = []
- for childOfChild in child.get_child_elements():
+ for gchild in child.get_child_elements():
- if childOfChild.get_tag() == gedcom.tags.GEDCOM_TAG_DATE:
- date = childOfChild.get_value()
+ if gchild.get_tag() == tags.GEDCOM_TAG_DATE:
+ date = gchild.get_value()
- if childOfChild.get_tag() == gedcom.tags.GEDCOM_TAG_PLACE:
- place = childOfChild.get_value()
+ if gchild.get_tag() == tags.GEDCOM_TAG_PLACE:
+ place = gchild.get_value()
- if childOfChild.get_tag() == gedcom.tags.GEDCOM_TAG_SOURCE:
- sources.append(childOfChild.get_value())
+ if gchild.get_tag() == tags.GEDCOM_TAG_SOURCE:
+ sources.append(gchild.get_value())
census.append((date, place, sources))
@@ -1323,57 +1432,55 @@
Returns the death data of a person formatted as a tuple: (str date, str place, list sources)
-:rtype: tuple
+
Returns the death data of a person formatted as a tuple:
+(str date, str place, list sources)
Expand source code
-
def get_death_data(self):
- """Returns the death data of a person formatted as a tuple: (`str` date, `str` place, `list` sources)
- :rtype: tuple
+
def get_death_data(self) -> Tuple[str, str, List[str]]:
+ """Returns the death data of a person formatted as a tuple:
+ (`str` date, `str` place, `list` sources)
"""
date = ""
place = ""
sources = []
for child in self.get_child_elements():
- if child.get_tag() == gedcom.tags.GEDCOM_TAG_DEATH:
- for childOfChild in child.get_child_elements():
- if childOfChild.get_tag() == gedcom.tags.GEDCOM_TAG_DATE:
- date = childOfChild.get_value()
- if childOfChild.get_tag() == gedcom.tags.GEDCOM_TAG_PLACE:
- place = childOfChild.get_value()
- if childOfChild.get_tag() == gedcom.tags.GEDCOM_TAG_SOURCE:
- sources.append(childOfChild.get_value())
+ if child.get_tag() == tags.GEDCOM_TAG_DEATH:
+ for gchild in child.get_child_elements():
+ if gchild.get_tag() == tags.GEDCOM_TAG_DATE:
+ date = gchild.get_value()
+ if gchild.get_tag() == tags.GEDCOM_TAG_PLACE:
+ place = gchild.get_value()
+ if gchild.get_tag() == tags.GEDCOM_TAG_SOURCE:
+ sources.append(gchild.get_value())
return date, place, sources
-def get_death_year(self)
+def get_death_year(self) -> int
-
Returns the death year of a person in integer format
-:rtype: int
+
Returns the death year of a person in integer format.
Expand source code
-
def get_death_year(self):
- """Returns the death year of a person in integer format
- :rtype: int
+
def get_death_year(self) -> int:
+ """Returns the death year of a person in integer format.
"""
date = ""
for child in self.get_child_elements():
- if child.get_tag() == gedcom.tags.GEDCOM_TAG_DEATH:
- for childOfChild in child.get_child_elements():
- if childOfChild.get_tag() == gedcom.tags.GEDCOM_TAG_DATE:
- date_split = childOfChild.get_value().split()
+ if child.get_tag() == tags.GEDCOM_TAG_DEATH:
+ for gchild in child.get_child_elements():
+ if gchild.get_tag() == tags.GEDCOM_TAG_DATE:
+ date_split = gchild.get_value().split()
date = date_split[len(date_split) - 1]
if date == "":
@@ -1385,77 +1492,72 @@
Returns the gender of a person in string format
-:rtype: str
+
Returns the gender of a person in string format.
Expand source code
-
def get_gender(self):
- """Returns the gender of a person in string format
- :rtype: str
+
def get_gender(self) -> str:
+ """Returns the gender of a person in string format.
"""
gender = ""
for child in self.get_child_elements():
- if child.get_tag() == gedcom.tags.GEDCOM_TAG_SEX:
+ if child.get_tag() == tags.GEDCOM_TAG_SEX:
gender = child.get_value()
return gender
Returns the date of when the person data was last changed formatted as a string
-:rtype: str
+
Returns the date of when the person data was last changed formatted as a string.
Expand source code
-
def get_last_change_date(self):
- """Returns the date of when the person data was last changed formatted as a string
- :rtype: str
+
def get_last_change_date(self) -> str:
+ """Returns the date of when the person data was last changed formatted as a string.
"""
date = ""
for child in self.get_child_elements():
- if child.get_tag() == gedcom.tags.GEDCOM_TAG_CHANGE:
- for childOfChild in child.get_child_elements():
- if childOfChild.get_tag() == gedcom.tags.GEDCOM_TAG_DATE:
- date = childOfChild.get_value()
+ if child.get_tag() == tags.GEDCOM_TAG_CHANGE:
+ for gchild in child.get_child_elements():
+ if gchild.get_tag() == tags.GEDCOM_TAG_DATE:
+ date = gchild.get_value()
return date
Returns an individual's names as a tuple: (str given_name, str surname)
-:rtype: tuple
+
Returns an individual's names as a tuple: (str given_name, str surname)
Expand source code
-
def get_name(self):
+
def get_name(self) -> Tuple[str, str]:
"""Returns an individual's names as a tuple: (`str` given_name, `str` surname)
- :rtype: tuple
"""
given_name = ""
surname = ""
- # Return the first gedcom.tags.GEDCOM_TAG_NAME that is found.
- # Alternatively as soon as we have both the gedcom.tags.GEDCOM_TAG_GIVEN_NAME and _SURNAME return those.
+ # Return the first tags.GEDCOM_TAG_NAME that is found.
+ # Alternatively as soon as we have both the tags.GEDCOM_TAG_GIVEN_NAME
+ # and _SURNAME return those.
found_given_name = False
found_surname_name = False
for child in self.get_child_elements():
- if child.get_tag() == gedcom.tags.GEDCOM_TAG_NAME:
+ if child.get_tag() == tags.GEDCOM_TAG_NAME:
# Some GEDCOM files don't use child tags but instead
# place the name in the value of the NAME tag.
if child.get_value() != "":
@@ -1468,14 +1570,14 @@
Methods
return given_name, surname
- for childOfChild in child.get_child_elements():
+ for gchild in child.get_child_elements():
- if childOfChild.get_tag() == gedcom.tags.GEDCOM_TAG_GIVEN_NAME:
- given_name = childOfChild.get_value()
+ if gchild.get_tag() == tags.GEDCOM_TAG_GIVEN_NAME:
+ given_name = gchild.get_value()
found_given_name = True
- if childOfChild.get_tag() == gedcom.tags.GEDCOM_TAG_SURNAME:
- surname = childOfChild.get_value()
+ if gchild.get_tag() == tags.GEDCOM_TAG_SURNAME:
+ surname = gchild.get_value()
found_surname_name = True
if found_given_name and found_surname_name:
@@ -1486,130 +1588,213 @@
def get_occupation(self):
- """Returns the occupation of a person
- :rtype: str
+
def get_occupation(self) -> str:
+ """Returns the occupation of a person.
"""
occupation = ""
for child in self.get_child_elements():
- if child.get_tag() == gedcom.tags.GEDCOM_TAG_OCCUPATION:
+ if child.get_tag() == tags.GEDCOM_TAG_OCCUPATION:
occupation = child.get_value()
return occupation
+
+def get_record(self) -> dict
+
+
+
Parse and return the full record in dictionary format.
+
+
+Expand source code
+
+
def get_record(self) -> dict:
+ """Parse and return the full record in dictionary format.
+ """
+ record = {
+ 'key_to_individual': self.get_pointer(),
+ 'restriction': '',
+ 'names': [],
+ 'sex': 'U',
+ 'events': individual_event_structure(self),
+ 'attributes': individual_attribute_structure(self),
+ 'child_to_family': [],
+ 'spouse_to_family': [],
+ 'submitters': [],
+ 'associates': [],
+ 'aliases': [],
+ 'ancestors_interest': [],
+ 'descendants_interest': [],
+ 'permanent_file_number': '',
+ 'ancestral_file_number': '',
+ 'references': [],
+ 'record_id': '',
+ 'change_date': {},
+ 'notes': [],
+ 'citations': [],
+ 'media': []
+ }
+ lds_events = lds_individual_ordinance(self)
+ if len(lds_events) > 0:
+ for event in lds_events:
+ record['events'].append(event)
+
+ for child in self.get_child_elements():
+ if child.get_tag() in INDIVIDUAL_SINGLE_TAGS:
+ record[INDIVIDUAL_SINGLE_TAGS[child.get_tag()]] = child.get_value()
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_NAME:
+ record['names'].append(personal_name_structure(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_FAMILY_CHILD:
+ record['child_to_family'].append(child_to_family_link(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_FAMILY_SPOUSE:
+ record['spouse_to_family'].append(spouse_to_family_link(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_NOTE:
+ record['notes'].append(note_structure(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_SOURCE:
+ record['citations'].append(source_citation(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_MEDIA:
+ record['media'].append(multimedia_link(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_SUBMITTER:
+ record['submitters'].append(child.get_value())
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_ASSOCIATES:
+ record['associates'].append(association_structure(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_ALIAS:
+ record['aliases'].append(child.get_value())
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_ANCES_INTEREST:
+ record['ancestors_interest'].append(child.get_value())
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_DESCENDANTS_INT:
+ record['descendants_interest'].append(child.get_value())
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_REFERENCE:
+ record['references'].append(user_reference_number(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_CHANGE:
+ record['changed'] = change_date(child)
+
+ return record
Matches a string with the given name of an individual
-::deprecated:: As of version 1.0.0 use given_name_match() method instead
-:type name: str
-:rtype: bool
+
Matches a string with the given name of an individual.
+::deprecated:: As of version 1.0.0 use given_name_match() method instead
Expand source code
@deprecated
-def given_match(self, name):
- """Matches a string with the given name of an individual
+def given_match(self, name: str) -> bool:
+ """Matches a string with the given name of an individual.
::deprecated:: As of version 1.0.0 use `given_name_match()` method instead
- :type name: str
- :rtype: bool
"""
return self.given_name_match(name)
Matches a string with the given name of an individual
-:type given_name_to_match: str
-:rtype: bool
+
Matches a string with the given name of an individual.
Expand source code
-
def given_name_match(self, given_name_to_match):
- """Matches a string with the given name of an individual
- :type given_name_to_match: str
- :rtype: bool
+
def given_name_match(self, given_name_to_match: str) -> bool:
+ """Matches a string with the given name of an individual.
"""
(given_name, surname) = self.get_name()
return regex.search(given_name_to_match, given_name, regex.IGNORECASE)
-def is_child(self)
+def is_child(self) -> bool
-
Checks if this element is a child of a family
-:rtype: bool
+
Checks if this element is a child of a family.
Expand source code
-
def is_child(self):
- """Checks if this element is a child of a family
- :rtype: bool
+
def is_child(self) -> bool:
+ """Checks if this element is a child of a family.
"""
found_child = False
for child in self.get_child_elements():
- if child.get_tag() == gedcom.tags.GEDCOM_TAG_FAMILY_CHILD:
+ if child.get_tag() == tags.GEDCOM_TAG_FAMILY_CHILD:
found_child = True
return found_child
Checks if this individual is deceased
-:rtype: bool
+
Checks if this individual is deceased.
Expand source code
-
def is_deceased(self):
- """Checks if this individual is deceased
- :rtype: bool
+
def is_deceased(self) -> bool:
+ """Checks if this individual is deceased.
"""
for child in self.get_child_elements():
- if child.get_tag() == gedcom.tags.GEDCOM_TAG_DEATH:
+ if child.get_tag() == tags.GEDCOM_TAG_DEATH:
return True
return False
Checks if this individual is marked private
-:rtype: bool
+
Checks if this individual is marked private.
Expand source code
-
def is_private(self):
- """Checks if this individual is marked private
- :rtype: bool
+
def is_private(self) -> bool:
+ """Checks if this individual is marked private.
"""
for child in self.get_child_elements():
- if child.get_tag() == gedcom.tags.GEDCOM_TAG_PRIVATE:
+ if child.get_tag() == tags.GEDCOM_TAG_PRIVATE:
private = child.get_value()
if private == 'Y':
return True
@@ -1618,20 +1803,16 @@
Matches a string with the surname of an individual
-:type surname_to_match: str
-:rtype: bool
+
Matches a string with the surname of an individual.
Expand source code
-
def surname_match(self, surname_to_match):
- """Matches a string with the surname of an individual
- :type surname_to_match: str
- :rtype: bool
+
def surname_match(self, surname_to_match: str) -> bool:
+ """Matches a string with the surname of an individual.
"""
(given_name, surname) = self.get_name()
return regex.search(surname_to_match, surname, regex.IGNORECASE)
@@ -1660,25 +1841,6 @@
Inherited members
-
-class NotAnActualIndividualError
-(...)
-
-
-
Common base class for all non-exit exceptions.
-
-
-Expand source code
-
-
class NotAnActualIndividualError(Exception):
- pass
GEDCOM element for a NOTE_RECORD note record identified by the
+GEDCOM_TAG_NOTE tag.
+
+
+Expand source code
+
+
# -*- coding: utf-8 -*-
+
+# Python GEDCOM Parser
+#
+# Copyright (C) 2020 Christopher Horn (cdhorn at embarqmail dot com)
+# Copyright (C) 2018 Damon Brodie (damon.brodie at gmail.com)
+# Copyright (C) 2018-2019 Nicklas Reincke (contact at reynke.com)
+# Copyright (C) 2016 Andreas Oberritter
+# Copyright (C) 2012 Madeleine Price Ball
+# Copyright (C) 2005 Daniel Zappala (zappala at cs.byu.edu)
+# Copyright (C) 2005 Brigham Young University
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Further information about the license: http://www.gnu.org/licenses/gpl-2.0.html
+
+"""
+GEDCOM element for a `NOTE_RECORD` note record identified by the
+`gedcom.tags.GEDCOM_TAG_NOTE` tag.
+"""
+
+import gedcom.tags as tags
+from gedcom.element.element import Element
+from gedcom.subparsers.source_citation import source_citation
+from gedcom.subparsers.change_date import change_date
+from gedcom.subparsers.user_reference_number import user_reference_number
+
+
+class NoteElement(Element):
+ """Element associated with a `NOTE_RECORD`"""
+
+ def get_tag(self) -> str:
+ return tags.GEDCOM_TAG_NOTE
+
+ def get_record(self) -> dict:
+ """Parse and return the full record in dictionary format.
+ """
+ record = {
+ 'key_to_note': self.get_pointer(),
+ 'note': self.get_multi_line_value(),
+ 'references': [],
+ 'record_id': '',
+ 'citations': [],
+ 'change_date': {}
+ }
+ for child in self.get_child_elements():
+ if child.get_tag() == tags.GEDCOM_TAG_REFERENCE:
+ record['references'].append(user_reference_number(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_REC_ID_NUMBER:
+ record['record_id'] = child.get_value()
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_SOURCE:
+ record['citations'].append(source_citation(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_CHANGE:
+ record['change_date'] = change_date(child)
+
+ return record
Each line in a GEDCOM file is an element with the format
-
level [pointer] tag [value]
-
where level and tag are required, and pointer and value are
-optional.
-Elements are arranged hierarchically according to their
-level, and elements with a level of zero are at the top level.
-Elements with a level greater than zero are children of their
-parent.
-
A pointer has the format @pname@, where pname is any sequence of
-characters and numbers. The pointer identifies the object being
-pointed to, so that any pointer included as the value of any
-element points back to the original object.
-For example, an
-element may have a FAMS tag whose value is @F1@, meaning that this
-element points to the family record in which the associated person
-is a spouse. Likewise, an element with a tag of FAMC has a value
-that points to a family record in which the associated person is a
-child.
-
See a GEDCOM file for examples of tags and their values.
-
Tags available to an element are seen here: gedcom.tags
+
Element associated with a MULTIMEDIA_RECORD
Expand source code
class ObjectElement(Element):
+ """Element associated with a `MULTIMEDIA_RECORD`"""
- def is_object(self):
- """Checks if this element is an actual object
- :rtype: bool
+ def get_tag(self) -> str:
+ return tags.GEDCOM_TAG_OBJECT
+
+ def get_record(self) -> dict:
+ """Parse and return the full record in dictionary format.
"""
- return self.get_tag() == gedcom.tags.GEDCOM_TAG_OBJECT
+ record = {
+ 'key_to_object': self.get_pointer(),
+ 'file': '',
+ 'format': '',
+ 'type': '',
+ 'title': '',
+ 'references': [],
+ 'record_id': '',
+ 'citations': [],
+ 'notes': [],
+ 'change_date': {}
+ }
+ for child in self.get_child_elements():
+ if child.get_tag() == tags.GEDCOM_TAG_FILE:
+ record['file'] = child.get_value()
+
+ for gchild in child.get_child_elements():
+ if gchild.get_tag() == tags.GEDCOM_TAG_FORMAT:
+ record['format'] = gchild.get_value()
+
+ for ggchild in gchild.get_child_elements():
+ if ggchild.get_tag() == tags.GEDCOM_TAG_TYPE:
+ record['type'] = ggchild.get_value()
+ continue
+
+ if gchild.get_tag() == tags.GEDCOM_TAG_TITLE:
+ record['title'] = gchild.get_value()
+ continue
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_FORMAT:
+ record['format'] = child.get_value()
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_TYPE:
+ record['type'] = child.get_value()
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_NOTE:
+ record['notes'].append(note_structure(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_SOURCE:
+ record['citations'].append(source_citation(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_REFERENCE:
+ record['references'].append(user_reference_number(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_REC_ID_NUMBER:
+ record['record_id'] = child.get_value()
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_CHANGE:
+ record['change_date'] = change_date(child)
+
+ return record
Ancestors
@@ -143,21 +230,76 @@
Ancestors
Methods
-
-def is_object(self)
+
+def get_record(self) -> dict
-
Checks if this element is an actual object
-:rtype: bool
+
Parse and return the full record in dictionary format.
Expand source code
-
def is_object(self):
- """Checks if this element is an actual object
- :rtype: bool
+
def get_record(self) -> dict:
+ """Parse and return the full record in dictionary format.
"""
- return self.get_tag() == gedcom.tags.GEDCOM_TAG_OBJECT
+ record = {
+ 'key_to_object': self.get_pointer(),
+ 'file': '',
+ 'format': '',
+ 'type': '',
+ 'title': '',
+ 'references': [],
+ 'record_id': '',
+ 'citations': [],
+ 'notes': [],
+ 'change_date': {}
+ }
+ for child in self.get_child_elements():
+ if child.get_tag() == tags.GEDCOM_TAG_FILE:
+ record['file'] = child.get_value()
+
+ for gchild in child.get_child_elements():
+ if gchild.get_tag() == tags.GEDCOM_TAG_FORMAT:
+ record['format'] = gchild.get_value()
+
+ for ggchild in gchild.get_child_elements():
+ if ggchild.get_tag() == tags.GEDCOM_TAG_TYPE:
+ record['type'] = ggchild.get_value()
+ continue
+
+ if gchild.get_tag() == tags.GEDCOM_TAG_TITLE:
+ record['title'] = gchild.get_value()
+ continue
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_FORMAT:
+ record['format'] = child.get_value()
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_TYPE:
+ record['type'] = child.get_value()
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_NOTE:
+ record['notes'].append(note_structure(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_SOURCE:
+ record['citations'].append(source_citation(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_REFERENCE:
+ record['references'].append(user_reference_number(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_REC_ID_NUMBER:
+ record['record_id'] = child.get_value()
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_CHANGE:
+ record['change_date'] = change_date(child)
+
+ return record
GEDCOM element for a REPOSITORY_RECORD repository record identified by the
+GEDCOM_TAG_REPOSITORY tag.
+
+
+Expand source code
+
+
# -*- coding: utf-8 -*-
+
+# Python GEDCOM Parser
+#
+# Copyright (C) 2020 Christopher Horn (cdhorn at embarqmail dot com)
+# Copyright (C) 2018 Damon Brodie (damon.brodie at gmail.com)
+# Copyright (C) 2018-2019 Nicklas Reincke (contact at reynke.com)
+# Copyright (C) 2016 Andreas Oberritter
+# Copyright (C) 2012 Madeleine Price Ball
+# Copyright (C) 2005 Daniel Zappala (zappala at cs.byu.edu)
+# Copyright (C) 2005 Brigham Young University
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Further information about the license: http://www.gnu.org/licenses/gpl-2.0.html
+
+"""
+GEDCOM element for a `REPOSITORY_RECORD` repository record identified by the
+`gedcom.tags.GEDCOM_TAG_REPOSITORY` tag.
+"""
+
+import gedcom.tags as tags
+from gedcom.element.element import Element
+from gedcom.subparsers.address_structure import address_structure
+from gedcom.subparsers.note_structure import note_structure
+from gedcom.subparsers.change_date import change_date
+from gedcom.subparsers.user_reference_number import user_reference_number
+
+
+class RepositoryElement(Element):
+ """Element associated with a `REPOSITORY_RECORD`"""
+
+ def get_tag(self) -> str:
+ return tags.GEDCOM_TAG_REPOSITORY
+
+ def get_record(self) -> dict:
+ """Parse and return the full record in dictionary format.
+ """
+ record = {
+ 'key_to_repository': self.get_pointer(),
+ 'name': '',
+ 'address': {},
+ 'references': [],
+ 'record_id': '',
+ 'change_date': {},
+ 'notes': []
+ }
+ for child in self.get_child_elements():
+ if child.get_tag() == tags.GEDCOM_TAG_NAME:
+ record['name'] = child.get_value()
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_ADDRESS:
+ record['address'] = address_structure(self)
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_NOTE:
+ record['notes'].append(note_structure(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_REFERENCE:
+ record['references'].append(user_reference_number(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_REC_ID_NUMBER:
+ record['record_id'] = child.get_value()
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_CHANGE:
+ record['change_date'] = change_date(child)
+
+ return record
GEDCOM element for a SOURCE_RECORD source record identified by the
+GEDCOM_TAG_SOURCE tag.
+
+
+Expand source code
+
+
# -*- coding: utf-8 -*-
+
+# Python GEDCOM Parser
+#
+# Copyright (C) 2020 Christopher Horn (cdhorn at embarqmail dot com)
+# Copyright (C) 2018 Damon Brodie (damon.brodie at gmail.com)
+# Copyright (C) 2018-2019 Nicklas Reincke (contact at reynke.com)
+# Copyright (C) 2016 Andreas Oberritter
+# Copyright (C) 2012 Madeleine Price Ball
+# Copyright (C) 2005 Daniel Zappala (zappala at cs.byu.edu)
+# Copyright (C) 2005 Brigham Young University
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Further information about the license: http://www.gnu.org/licenses/gpl-2.0.html
+
+"""
+GEDCOM element for a `SOURCE_RECORD` source record identified by the
+`gedcom.tags.GEDCOM_TAG_SOURCE` tag.
+"""
+
+import gedcom.tags as tags
+from gedcom.element.element import Element
+from gedcom.subparsers.change_date import change_date
+from gedcom.subparsers.note_structure import note_structure
+from gedcom.subparsers.multimedia_link import multimedia_link
+from gedcom.subparsers.user_reference_number import user_reference_number
+from gedcom.subparsers.source_repository_citation import source_repository_citation
+
+SOURCE_PLURAL_TAGS = {
+ tags.GEDCOM_TAG_AUTHOR: 'author',
+ tags.GEDCOM_TAG_TITLE: 'title',
+ tags.GEDCOM_TAG_PUBLICATION: 'publication',
+ tags.GEDCOM_TAG_TEXT: 'text'
+}
+
+SOURCE_SINGLE_TAGS = {
+ tags.GEDCOM_TAG_ABBREVIATION: 'abbreviation',
+ tags.GEDCOM_TAG_REC_ID_NUMBER: 'record_id',
+ tags.GEDCOM_PROGRAM_DEFINED_TAG_APID: 'apid'
+}
+
+
+class SourceElement(Element):
+ """Element associated with a SOURCE_RECORD"""
+
+ def get_tag(self) -> str:
+ return tags.GEDCOM_TAG_SOURCE
+
+ def get_record(self) -> dict:
+ """Parse and return the full record in dictionary format.
+ """
+ record = {
+ 'key_to_source': self.get_pointer(),
+ 'data': {
+ 'events': '',
+ 'date': '',
+ 'place': '',
+ 'agency': '',
+ 'notes': []
+ },
+ 'author': '',
+ 'title': '',
+ 'abbreviation': '',
+ 'publication': '',
+ 'text': '',
+ 'repository': {},
+ 'references': [],
+ 'record_id': '',
+ 'change_date': {},
+ 'notes': [],
+ 'media': [],
+ 'apid': ''
+ }
+ for child in self.get_child_elements():
+ if child.get_tag() in SOURCE_PLURAL_TAGS:
+ record[SOURCE_PLURAL_TAGS[child.get_tag()]] = child.get_multi_line_value()
+ continue
+
+ if child.get_tag() in SOURCE_SINGLE_TAGS:
+ record[SOURCE_SINGLE_TAGS[child.get_tag()]] = child.get_value()
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_NOTE:
+ record['notes'].append(note_structure(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_OBJECT:
+ record['media'].append(multimedia_link(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_REPOSITORY:
+ record['repository'] = source_repository_citation(child)
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_DATA:
+ for gchild in child.get_child_elements():
+ if gchild.get_tag() == tags.GEDCOM_TAG_EVENT:
+ record['data']['events'] = gchild.get_value()
+ for ggchild in gchild.get_child_elements():
+ if ggchild.get_tag() == tags.GEDCOM_TAG_DATE:
+ record['data']['date'] = ggchild.get_value()
+ continue
+
+ if ggchild.get_tag() == tags.GEDCOM_TAG_PLACE:
+ record['data']['place'] = ggchild.get_value()
+ continue
+
+ if gchild.get_tag() == tags.GEDCOM_TAG_AGENCY:
+ record['data']['agency'] = gchild.get_value()
+ continue
+
+ if gchild.get_tag() == tags.GEDCOM_TAG_NOTE:
+ record['data']['notes'].append(note_structure(gchild))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_REFERENCE:
+ record['references'].append(user_reference_number(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_CHANGE:
+ record['change_date'] = change_date(child)
+ continue
+
+ return record
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/gedcom/element/submission.html b/docs/gedcom/element/submission.html
new file mode 100644
index 0000000..c4bdb9e
--- /dev/null
+++ b/docs/gedcom/element/submission.html
@@ -0,0 +1,270 @@
+
+
+
+
+
+
+gedcom.element.submission API documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
Module gedcom.element.submission
+
+
+
GEDCOM element for a SUBMISSION_RECORD submission record identified by the
+GEDCOM_TAG_SUBMISSION tag.
+
+
+Expand source code
+
+
# -*- coding: utf-8 -*-
+
+# Python GEDCOM Parser
+#
+# Copyright (C) 2020 Christopher Horn (cdhorn at embarqmail dot com)
+# Copyright (C) 2018 Damon Brodie (damon.brodie at gmail.com)
+# Copyright (C) 2018-2019 Nicklas Reincke (contact at reynke.com)
+# Copyright (C) 2016 Andreas Oberritter
+# Copyright (C) 2012 Madeleine Price Ball
+# Copyright (C) 2005 Daniel Zappala (zappala at cs.byu.edu)
+# Copyright (C) 2005 Brigham Young University
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Further information about the license: http://www.gnu.org/licenses/gpl-2.0.html
+
+"""
+GEDCOM element for a `SUBMISSION_RECORD` submission record identified by the
+`gedcom.tags.GEDCOM_TAG_SUBMISSION` tag.
+"""
+
+import gedcom.tags as tags
+from gedcom.element.element import Element
+from gedcom.subparsers.note_structure import note_structure
+from gedcom.subparsers.change_date import change_date
+
+SUBMISSION_TAGS = {
+ tags.GEDCOM_TAG_SUBMITTER: 'key_to_submitter',
+ tags.GEDCOM_TAG_FAMILY_FILE: 'family_file',
+ tags.GEDCOM_TAG_TEMPLE: 'temple',
+ tags.GEDCOM_TAG_ANCESTORS: 'generations_of_ancestors',
+ tags.GEDCOM_TAG_DESCENDANTS: 'generations_of_decendants',
+ tags.GEDCOM_TAG_ORDINANCE: 'ordinance_process_flag',
+ tags.GEDCOM_TAG_REC_ID_NUMBER: 'record_id'
+}
+
+
+class SubmissionElement(Element):
+ """Element associated with a `SUBMISSION_RECORD`"""
+
+ def get_tag(self) -> str:
+ return tags.GEDCOM_TAG_SUBMISSION
+
+ def get_record(self) -> dict:
+ """Parse and return the record in dictionary format
+ """
+ record = {
+ 'key_to_submission': self.get_pointer(),
+ 'key_to_submitter': '',
+ 'family_file': '',
+ 'temple': '',
+ 'generations_of_ancestors': '',
+ 'generations_of_descendants': '',
+ 'ordinance_process_flag': '',
+ 'record_id': '',
+ 'notes': [],
+ 'change_date': {}
+ }
+ for child in self.get_child_elements():
+ if child.get_tag() in SUBMISSION_TAGS:
+ record[SUBMISSION_TAGS[child.get_tag()]] = child.get_value()
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_NOTE:
+ record['notes'].append(note_structure(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_CHANGE:
+ record['change_date'] = change_date(child)
+
+ return record
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/gedcom/element/submitter.html b/docs/gedcom/element/submitter.html
new file mode 100644
index 0000000..899e7ec
--- /dev/null
+++ b/docs/gedcom/element/submitter.html
@@ -0,0 +1,319 @@
+
+
+
+
+
+
+gedcom.element.submitter API documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
Module gedcom.element.submitter
+
+
+
GEDCOM element for a SUBMITTER_RECORD submitter record identified by the
+GEDCOM_TAG_SUBMITTER tag.
+
+
+Expand source code
+
+
# -*- coding: utf-8 -*-
+
+# Python GEDCOM Parser
+#
+# Copyright (C) 2020 Christopher Horn (cdhorn at embarqmail dot com)
+# Copyright (C) 2018 Damon Brodie (damon.brodie at gmail.com)
+# Copyright (C) 2018-2019 Nicklas Reincke (contact at reynke.com)
+# Copyright (C) 2016 Andreas Oberritter
+# Copyright (C) 2012 Madeleine Price Ball
+# Copyright (C) 2005 Daniel Zappala (zappala at cs.byu.edu)
+# Copyright (C) 2005 Brigham Young University
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Further information about the license: http://www.gnu.org/licenses/gpl-2.0.html
+
+"""
+GEDCOM element for a `SUBMITTER_RECORD` submitter record identified by the
+`gedcom.tags.GEDCOM_TAG_SUBMITTER` tag.
+"""
+
+import gedcom.tags as tags
+from gedcom.element.element import Element
+from gedcom.subparsers.address_structure import address_structure
+from gedcom.subparsers.note_structure import note_structure
+from gedcom.subparsers.change_date import change_date
+from gedcom.subparsers.multimedia_link import multimedia_link
+
+
+class SubmitterElement(Element):
+ """Element associated with a `SUBMITTER_RECORD`"""
+
+ def get_tag(self) -> str:
+ return tags.GEDCOM_TAG_SUBMITTER
+
+ def get_record(self) -> dict:
+ """Parse and return the record in dictionary format
+ """
+ record = {
+ 'key_to_submitter': self.get_pointer(),
+ 'name': '',
+ 'address': {},
+ 'media': [],
+ 'language': '',
+ 'registered_file_number': '',
+ 'record_id': '',
+ 'notes': [],
+ 'change_date': {}
+ }
+ for child in self.get_child_elements():
+ if child.get_tag() == tags.GEDCOM_TAG_NAME:
+ record['name'] = child.get_value()
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_ADDRESS:
+ record['address'] = address_structure(self)
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_NOTE:
+ record['notes'].append(note_structure(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_OBJECT:
+ record['media'].append(multimedia_link(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_LANGUAGE:
+ record['language'] = child.get_value()
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_REC_FILE_NUMBER:
+ record['registered_file_number'] = child.get_value()
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_REC_ID_NUMBER:
+ record['record_id'] = child.get_value()
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_CHANGE:
+ record['change_date'] = change_date(child)
+
+ return record
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/gedcom/errors.html b/docs/gedcom/errors.html
new file mode 100644
index 0000000..bc3b49f
--- /dev/null
+++ b/docs/gedcom/errors.html
@@ -0,0 +1,495 @@
+
+
+
+
+
+
+gedcom.errors API documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
Module gedcom.errors
+
+
+
Module containing the exception handling classes.
+
+
+Expand source code
+
+
# -*- coding: utf-8 -*-
+
+# Python GEDCOM Parser
+#
+# Copyright (C) 2020 Christopher Horn (cdhorn at embarqmail dot com)
+# Copyright (C) 2018 Damon Brodie (damon.brodie at gmail.com)
+# Copyright (C) 2018-2019 Nicklas Reincke (contact at reynke.com)
+# Copyright (C) 2016 Andreas Oberritter
+# Copyright (C) 2012 Madeleine Price Ball
+# Copyright (C) 2005 Daniel Zappala (zappala at cs.byu.edu)
+# Copyright (C) 2005 Brigham Young University
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Further information about the license: http://www.gnu.org/licenses/gpl-2.0.html
+
+"""
+Module containing the exception handling classes.
+"""
+
+
+class GedcomFormatViolationError(Exception):
+ """Raised when the document format does not appear to conform
+ to the GEDCOM standard and strict parsing required.
+ """
+
+
+class GedcomStructureViolationError(Exception):
+ """Raised when the structure of a record does not conform to
+ the GEDCOM standard.
+ """
+
+
+class GedcomCharacterSetUnsupportedError(Exception):
+ """Raised when a GEDCOM appears to contain a character set
+ the standard or the parser does not support.
+ """
+
+
+class GedcomVersionUnsupportedError(Exception):
+ """Raised when a particular GEDCOM version is not supported
+ by the parser and the standard for that version requires the
+ parser to reject it.
+ """
+
+
+class GedcomFormatUnsupportedError(Exception):
+ """Raised if the GEDCOM format is not recognized by the
+ parser. Note some common misspellings as documented on page 148
+ in the 5.5.5 GEDCOM standard are treated as `LINEAGE-LINKED`
+ and allowed when parsing older GEDCOM data.
+ """
+
+
+class NotAnActualIndividualError(Exception):
+ """Raised if record does not appear to be an `INDIVIDUAL_RECORD`"""
+
+
+class NotAnActualFamilyError(Exception):
+ """Raised if record does not appear to be a `FAM_RECORD`"""
+
+
+class NotAnActualSourceError(Exception):
+ """Raised if record does not appear to be a `SOURCE_RECORD`"""
+
+
+class NotAnActualRepositoryError(Exception):
+ """Raised if record does not appear to be a `REPOSITORY_RECORD`"""
+
+
+class NotAnActualNoteError(Exception):
+ """Raised if record does not appear to be a `NOTE_RECORD`"""
+
+
+class NotAnActualObjectError(Exception):
+ """Raised if record does not appear to be a `MULTIMEDIA_RECORD`"""
+
+
+class NotAnActualHeaderError(Exception):
+ """Raised if record does not appear to be a `HEADER`"""
+
+
+class NotAnActualSubmitterError(Exception):
+ """Raised if record does not appear to be a `SUBMITTER_RECORD`"""
+
+
+class NotAnActualSubmissionError(Exception):
+ """Raised if record does not appear to be a `SUBMISSION_RECORD`"""
Raised when a GEDCOM appears to contain a character set
+the standard or the parser does not support.
+
+
+Expand source code
+
+
class GedcomCharacterSetUnsupportedError(Exception):
+ """Raised when a GEDCOM appears to contain a character set
+ the standard or the parser does not support.
+ """
+
+
Ancestors
+
+
builtins.Exception
+
builtins.BaseException
+
+
+
+class GedcomFormatUnsupportedError
+(...)
+
+
+
Raised if the GEDCOM format is not recognized by the
+parser. Note some common misspellings as documented on page 148
+in the 5.5.5 GEDCOM standard are treated as LINEAGE-LINKED
+and allowed when parsing older GEDCOM data.
+
+
+Expand source code
+
+
class GedcomFormatUnsupportedError(Exception):
+ """Raised if the GEDCOM format is not recognized by the
+ parser. Note some common misspellings as documented on page 148
+ in the 5.5.5 GEDCOM standard are treated as `LINEAGE-LINKED`
+ and allowed when parsing older GEDCOM data.
+ """
+
+
Ancestors
+
+
builtins.Exception
+
builtins.BaseException
+
+
+
+class GedcomFormatViolationError
+(...)
+
+
+
Raised when the document format does not appear to conform
+to the GEDCOM standard and strict parsing required.
+
+
+Expand source code
+
+
class GedcomFormatViolationError(Exception):
+ """Raised when the document format does not appear to conform
+ to the GEDCOM standard and strict parsing required.
+ """
+
+
Ancestors
+
+
builtins.Exception
+
builtins.BaseException
+
+
+
+class GedcomStructureViolationError
+(...)
+
+
+
Raised when the structure of a record does not conform to
+the GEDCOM standard.
+
+
+Expand source code
+
+
class GedcomStructureViolationError(Exception):
+ """Raised when the structure of a record does not conform to
+ the GEDCOM standard.
+ """
+
+
Ancestors
+
+
builtins.Exception
+
builtins.BaseException
+
+
+
+class GedcomVersionUnsupportedError
+(...)
+
+
+
Raised when a particular GEDCOM version is not supported
+by the parser and the standard for that version requires the
+parser to reject it.
+
+
+Expand source code
+
+
class GedcomVersionUnsupportedError(Exception):
+ """Raised when a particular GEDCOM version is not supported
+ by the parser and the standard for that version requires the
+ parser to reject it.
+ """
+
+
Ancestors
+
+
builtins.Exception
+
builtins.BaseException
+
+
+
+class NotAnActualFamilyError
+(...)
+
+
+
Raised if record does not appear to be a FAM_RECORD
+
+
+Expand source code
+
+
class NotAnActualFamilyError(Exception):
+ """Raised if record does not appear to be a `FAM_RECORD`"""
+
+
Ancestors
+
+
builtins.Exception
+
builtins.BaseException
+
+
+
+class NotAnActualHeaderError
+(...)
+
+
+
Raised if record does not appear to be a HEADER
+
+
+Expand source code
+
+
class NotAnActualHeaderError(Exception):
+ """Raised if record does not appear to be a `HEADER`"""
+
+
Ancestors
+
+
builtins.Exception
+
builtins.BaseException
+
+
+
+class NotAnActualIndividualError
+(...)
+
+
+
Raised if record does not appear to be an INDIVIDUAL_RECORD
+
+
+Expand source code
+
+
class NotAnActualIndividualError(Exception):
+ """Raised if record does not appear to be an `INDIVIDUAL_RECORD`"""
+
+
Ancestors
+
+
builtins.Exception
+
builtins.BaseException
+
+
+
+class NotAnActualNoteError
+(...)
+
+
+
Raised if record does not appear to be a NOTE_RECORD
+
+
+Expand source code
+
+
class NotAnActualNoteError(Exception):
+ """Raised if record does not appear to be a `NOTE_RECORD`"""
+
+
Ancestors
+
+
builtins.Exception
+
builtins.BaseException
+
+
+
+class NotAnActualObjectError
+(...)
+
+
+
Raised if record does not appear to be a MULTIMEDIA_RECORD
+
+
+Expand source code
+
+
class NotAnActualObjectError(Exception):
+ """Raised if record does not appear to be a `MULTIMEDIA_RECORD`"""
+
+
Ancestors
+
+
builtins.Exception
+
builtins.BaseException
+
+
+
+class NotAnActualRepositoryError
+(...)
+
+
+
Raised if record does not appear to be a REPOSITORY_RECORD
+
+
+Expand source code
+
+
class NotAnActualRepositoryError(Exception):
+ """Raised if record does not appear to be a `REPOSITORY_RECORD`"""
+
+
Ancestors
+
+
builtins.Exception
+
builtins.BaseException
+
+
+
+class NotAnActualSourceError
+(...)
+
+
+
Raised if record does not appear to be a SOURCE_RECORD
+
+
+Expand source code
+
+
class NotAnActualSourceError(Exception):
+ """Raised if record does not appear to be a `SOURCE_RECORD`"""
+
+
Ancestors
+
+
builtins.Exception
+
builtins.BaseException
+
+
+
+class NotAnActualSubmissionError
+(...)
+
+
+
Raised if record does not appear to be a SUBMISSION_RECORD
+
+
+Expand source code
+
+
class NotAnActualSubmissionError(Exception):
+ """Raised if record does not appear to be a `SUBMISSION_RECORD`"""
+
+
Ancestors
+
+
builtins.Exception
+
builtins.BaseException
+
+
+
+class NotAnActualSubmitterError
+(...)
+
+
+
Raised if record does not appear to be a SUBMITTER_RECORD
+
+
+Expand source code
+
+
class NotAnActualSubmitterError(Exception):
+ """Raised if record does not appear to be a `SUBMITTER_RECORD`"""
+
+
Ancestors
+
+
builtins.Exception
+
builtins.BaseException
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/gedcom/helpers.html b/docs/gedcom/helpers.html
index 783b4cd..8543391 100644
--- a/docs/gedcom/helpers.html
+++ b/docs/gedcom/helpers.html
@@ -3,14 +3,14 @@
-
+
gedcom.helpers API documentation
-
-
+
+
@@ -90,9 +90,9 @@
Functions
def deprecated(func)
-
This is a decorator which can be used to mark functions
+
This is a decorator which can be used to mark functions
as deprecated. It will result in a warning being emitted
-when the function is used.
Module containing the actual Parser used to generate elements - out of each line -
-which can in return be manipulated.
+
Module containing the actual Parser used to generate elements
+out of each line - which can in return be manipulated.
Expand source code
@@ -31,6 +31,7 @@
Module gedcom.parser
# Python GEDCOM Parser
#
+# Copyright (C) 2020 Christopher Horn (cdhorn at embarqmail dot com)
# Copyright (C) 2018 Damon Brodie (damon.brodie at gmail.com)
# Copyright (C) 2018-2019 Nicklas Reincke (contact at reynke.com)
# Copyright (C) 2016 Andreas Oberritter
@@ -55,35 +56,63 @@
Module gedcom.parser
# Further information about the license: http://www.gnu.org/licenses/gpl-2.0.html
"""
-Module containing the actual `gedcom.parser.Parser` used to generate elements - out of each line -
-which can in return be manipulated.
+Module containing the actual `gedcom.parser.Parser` used to generate elements
+out of each line - which can in return be manipulated.
"""
import re as regex
+from sys import stdout
from sys import version_info
+from typing import Tuple, List, IO
+
+import gedcom.tags as tags
+import gedcom.standards as standards
+
+from gedcom.detect import get_encoding, get_version
from gedcom.element.element import Element
-from gedcom.element.family import FamilyElement, NotAnActualFamilyError
-from gedcom.element.file import FileElement
-from gedcom.element.individual import IndividualElement, NotAnActualIndividualError
+from gedcom.element.header import HeaderElement
+from gedcom.element.family import FamilyElement
+from gedcom.element.individual import IndividualElement
+from gedcom.element.note import NoteElement
from gedcom.element.object import ObjectElement
+from gedcom.element.source import SourceElement
+from gedcom.element.submission import SubmissionElement
+from gedcom.element.submitter import SubmitterElement
+from gedcom.element.repository import RepositoryElement
from gedcom.element.root import RootElement
-import gedcom.tags
+
+from gedcom.errors import GedcomVersionUnsupportedError
+from gedcom.errors import GedcomFormatUnsupportedError
+from gedcom.errors import GedcomFormatViolationError
+from gedcom.errors import NotAnActualIndividualError
+from gedcom.errors import NotAnActualFamilyError
+
+ERROR_TEMPLATE = "Line <{0}:{1}> of document violates GEDCOM format {2}\nSee: {3}"
+
+RECORD_ELEMENTS = {
+ tags.GEDCOM_TAG_HEADER: HeaderElement,
+ tags.GEDCOM_TAG_INDIVIDUAL: IndividualElement,
+ tags.GEDCOM_TAG_FAMILY: FamilyElement,
+ tags.GEDCOM_TAG_NOTE: NoteElement,
+ tags.GEDCOM_TAG_OBJECT: ObjectElement,
+ tags.GEDCOM_TAG_SOURCE: SourceElement,
+ tags.GEDCOM_TAG_SUBMISSION: SubmissionElement,
+ tags.GEDCOM_TAG_SUBMITTER: SubmitterElement,
+ tags.GEDCOM_TAG_REPOSITORY: RepositoryElement
+}
FAMILY_MEMBERS_TYPE_ALL = "ALL"
-FAMILY_MEMBERS_TYPE_CHILDREN = gedcom.tags.GEDCOM_TAG_CHILD
-FAMILY_MEMBERS_TYPE_HUSBAND = gedcom.tags.GEDCOM_TAG_HUSBAND
+FAMILY_MEMBERS_TYPE_CHILDREN = tags.GEDCOM_TAG_CHILD
+FAMILY_MEMBERS_TYPE_HUSBAND = tags.GEDCOM_TAG_HUSBAND
FAMILY_MEMBERS_TYPE_PARENTS = "PARENTS"
-FAMILY_MEMBERS_TYPE_WIFE = gedcom.tags.GEDCOM_TAG_WIFE
+FAMILY_MEMBERS_TYPE_WIFE = tags.GEDCOM_TAG_WIFE
-class GedcomFormatViolationError(Exception):
- pass
+class Parser():
+ """Parses and manipulates GEDCOM formatted data.
-
-class Parser(object):
- """Parses and manipulates GEDCOM 5.5 format data
-
- For documentation of the GEDCOM 5.5 format, see: http://homepages.rootsweb.ancestry.com/~pmcbride/gedcom/55gctoc.htm
+ For documentation of the different GEDCOM standards see the
+ links defined in `gedcom.standards`
This parser reads and parses a GEDCOM file.
@@ -99,35 +128,36 @@
Module gedcom.parser
self.__root_element = RootElement()
def invalidate_cache(self):
- """Empties the element list and dictionary to cause `gedcom.parser.Parser.get_element_list()`
- and `gedcom.parser.Parser.get_element_dictionary()` to return updated data.
+ """Empties the element list and dictionary to cause
+ `gedcom.parser.Parser.get_element_list()` and
+ `gedcom.parser.Parser.get_element_dictionary()` to return updated data.
The update gets deferred until each of the methods actually gets called.
"""
self.__element_list = []
self.__element_dictionary = {}
- def get_element_list(self):
- """Returns a list containing all elements from within the GEDCOM file
+ def get_element_list(self) -> List[Element]:
+ """Returns a list containing all elements from within the GEDCOM file.
By default elements are in the same order as they appeared in the file.
This list gets generated on-the-fly, but gets cached. If the database
- was modified, you should call `gedcom.parser.Parser.invalidate_cache()` once to let this
- method return updated data.
+ was modified, you should call `gedcom.parser.Parser.invalidate_cache()` once
+ to let this method return updated data.
- Consider using `gedcom.parser.Parser.get_root_element()` or `gedcom.parser.Parser.get_root_child_elements()` to access
+ Consider using `gedcom.parser.Parser.get_root_element()` or
+ `gedcom.parser.Parser.get_root_child_elements()` to access
the hierarchical GEDCOM tree, unless you rarely modify the database.
-
- :rtype: list of Element
"""
if not self.__element_list:
for element in self.get_root_child_elements():
self.__build_list(element, self.__element_list)
return self.__element_list
- def get_element_dictionary(self):
- """Returns a dictionary containing all elements, identified by a pointer, from within the GEDCOM file
+ def get_element_dictionary(self) -> dict:
+ """Returns a dictionary containing all elements, identified by a pointer,
+ from within the GEDCOM file.
Only elements identified by a pointer are listed in the dictionary.
The keys for the dictionary are the pointers.
@@ -135,46 +165,51 @@
Module gedcom.parser
This dictionary gets generated on-the-fly, but gets cached. If the
database was modified, you should call `invalidate_cache()` once to let
this method return updated data.
-
- :rtype: dict of Element
"""
if not self.__element_dictionary:
self.__element_dictionary = {
- element.get_pointer(): element for element in self.get_root_child_elements() if element.get_pointer()
+ element.get_pointer():
+ element for element in self.get_root_child_elements() if element.get_pointer()
}
return self.__element_dictionary
- def get_root_element(self):
- """Returns a virtual root element containing all logical records as children
+ def get_root_element(self) -> RootElement:
+ """Returns a virtual root element containing all logical records as children.
When printed, this element converts to an empty string.
-
- :rtype: RootElement
"""
return self.__root_element
- def get_root_child_elements(self):
- """Returns a list of logical records in the GEDCOM file
+ def get_root_child_elements(self) -> List[Element]:
+ """Returns a list of logical records in the GEDCOM file.
By default, elements are in the same order as they appeared in the file.
-
- :rtype: list of Element
"""
return self.get_root_element().get_child_elements()
- def parse_file(self, file_path, strict=True):
- """Opens and parses a file, from the given file path, as GEDCOM 5.5 formatted data
- :type file_path: str
- :type strict: bool
+ def parse_file(self, file_path: str, strict: bool = True):
+ """Opens and parses a file, from the given file path, as GEDCOM formatted data.
"""
- with open(file_path, 'rb') as gedcom_stream:
+ codec = get_encoding(file_path)
+ real_version, reported_version, reported_format = get_version(file_path, codec)
+
+ if reported_version == '5.5.5':
+ errmsg = "This parser does not properly support the GEDCOM " + reported_version + \
+ " standard at this time\nSee: {0}".format(standards.GEDCOM_5_5_5)
+ raise GedcomVersionUnsupportedError(errmsg)
+
+ if reported_format not in ['LINEAGE-LINKED', 'LINEAGE_LINKED',
+ 'LINAGE-LINKED', 'Lineage - Linked']:
+ errmsg = "This parser does not recognize the GEDCOM format " + reported_format + \
+ " at this time\nSee: {0}".format(standards.GEDCOM_5_5_5)
+ raise GedcomFormatUnsupportedError(errmsg)
+
+ with open(file_path, 'r', encoding=codec) as gedcom_stream:
self.parse(gedcom_stream, strict)
- def parse(self, gedcom_stream, strict=True):
- """Parses a stream, or an array of lines, as GEDCOM 5.5 formatted data
- :type gedcom_stream: a file stream, or str array of lines with new line at the end
- :type strict: bool
+ def parse(self, gedcom_stream: IO, strict: bool = True):
+ """Parses a stream, or an array of lines, as GEDCOM formatted data.
"""
self.invalidate_cache()
self.__root_element = RootElement()
@@ -183,24 +218,18 @@
Module gedcom.parser
last_element = self.get_root_element()
for line in gedcom_stream:
- last_element = self.__parse_line(line_number, line.decode('utf-8-sig'), last_element, strict)
+ last_element = self.__parse_line(line_number, line, last_element, strict)
line_number += 1
# Private methods
@staticmethod
- def __parse_line(line_number, line, last_element, strict=True):
- """Parse a line from a GEDCOM 5.5 formatted document
+ def __parse_line(line_number: int, line: str, last_element: Element,
+ strict: bool = True) -> Element:
+ """Parse a line from a GEDCOM 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.
@@ -219,43 +248,43 @@
Module gedcom.parser
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
+ 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:%s> of document violates GEDCOM format 5.5" % (line_number, line)
- + "\nSee: https://chronoplexsoftware.com/gedcomvalidator/gedcom/gedcom-5.5.pdf")
- raise GedcomFormatViolationError(error_message)
+ errmsg = ERROR_TEMPLATE.format(line_number, line, '5.5.1', standards.GEDCOM_5_5_1)
+ raise GedcomFormatViolationError(errmsg)
+
+ # 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 - 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
+ # 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 not in [tags.GEDCOM_TAG_CONTINUED, tags.GEDCOM_TAG_CONCATENATION]:
+ # Increment level and change this line to a CONC
+ level += 1
+ tag = tags.GEDCOM_TAG_CONCATENATION
else:
line_parts = regex_match.groups()
@@ -267,20 +296,14 @@
Module gedcom.parser
# 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)
+ errmsg = "Line {0} of document violates GEDCOM format 5.5.1\n".format(line_number) + \
+ "Lines must be no more than one level higher than previous line.\n" + \
+ "See: {0}".format(standards.GEDCOM_5_5_1)
+ raise GedcomFormatViolationError(errmsg)
# 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)
+ if tag in RECORD_ELEMENTS:
+ element = RECORD_ELEMENTS[tag](level, pointer, tag, value, crlf, multi_line=False)
else:
element = Element(level, pointer, tag, value, crlf, multi_line=False)
@@ -295,10 +318,8 @@
Module gedcom.parser
return element
- def __build_list(self, element, element_list):
- """Recursively add elements to a list containing elements
- :type element: Element
- :type element_list: list of Element
+ def __build_list(self, element: Element, element_list: List[Element]):
+ """Recursively add elements to a list containing elements.
"""
element_list.append(element)
for child in element.get_child_elements():
@@ -306,81 +327,74 @@
Module gedcom.parser
# Methods for analyzing individuals and relationships between individuals
- 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
+ def get_marriages(self, individual: IndividualElement) -> Tuple[str, str]:
+ """Returns a list of marriages of an individual formatted as a tuple:
+ (`str` date, `str` place)
"""
marriages = []
if not isinstance(individual, IndividualElement):
raise NotAnActualIndividualError(
- "Operation only valid for elements with %s tag" % gedcom.tags.GEDCOM_TAG_INDIVIDUAL
+ "Operation only valid for elements with %s tag" % tags.GEDCOM_TAG_INDIVIDUAL
)
# Get and analyze families where individual is spouse.
- families = self.get_families(individual, gedcom.tags.GEDCOM_TAG_FAMILY_SPOUSE)
+ families = self.get_families(individual, 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:
+ if family_data.get_tag() == 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:
+ if marriage_data.get_tag() == tags.GEDCOM_TAG_DATE:
date = marriage_data.get_value()
- if marriage_data.get_tag() == gedcom.tags.GEDCOM_TAG_PLACE:
+ if marriage_data.get_tag() == tags.GEDCOM_TAG_PLACE:
place = marriage_data.get_value()
marriages.append((date, place))
return marriages
- def get_marriage_years(self, individual):
- """Returns a list of marriage years (as integers) for an individual
- :type individual: IndividualElement
- :rtype: list of int
+ def get_marriage_years(self, individual: IndividualElement) -> List[int]:
+ """Returns a list of marriage years for an individual.
"""
dates = []
if not isinstance(individual, IndividualElement):
raise NotAnActualIndividualError(
- "Operation only valid for elements with %s tag" % gedcom.tags.GEDCOM_TAG_INDIVIDUAL
+ "Operation only valid for elements with %s tag" % tags.GEDCOM_TAG_INDIVIDUAL
)
# Get and analyze families where individual is spouse.
- families = self.get_families(individual, gedcom.tags.GEDCOM_TAG_FAMILY_SPOUSE)
+ families = self.get_families(individual, 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]
+ if child.get_tag() == tags.GEDCOM_TAG_MARRIAGE:
+ for gchild in child.get_child_elements():
+ if gchild.get_tag() == tags.GEDCOM_TAG_DATE:
+ date = gchild.get_value().split()[-1]
try:
dates.append(int(date))
except ValueError:
pass
return dates
- 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
+ def marriage_year_match(self, individual: IndividualElement, year: int) -> bool:
+ """Checks if one of the marriage years of an individual matches the supplied year.
+ Year is an integer.
"""
if not isinstance(individual, IndividualElement):
raise NotAnActualIndividualError(
- "Operation only valid for elements with %s tag" % gedcom.tags.GEDCOM_TAG_INDIVIDUAL
+ "Operation only valid for elements with %s tag" % 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
+ def marriage_range_match(self, individual: IndividualElement,
+ from_year: int, to_year: int) -> bool:
+ """Check if one of the marriage years of an individual is in a given range.
+ Years are integers.
"""
if not isinstance(individual, IndividualElement):
raise NotAnActualIndividualError(
- "Operation only valid for elements with %s tag" % gedcom.tags.GEDCOM_TAG_INDIVIDUAL
+ "Operation only valid for elements with %s tag" % tags.GEDCOM_TAG_INDIVIDUAL
)
years = self.get_marriage_years(individual)
@@ -389,20 +403,19 @@
Module gedcom.parser
return True
return False
- def get_families(self, individual, family_type=gedcom.tags.GEDCOM_TAG_FAMILY_SPOUSE):
- """Return family elements listed for an individual
+ def get_families(self, individual: IndividualElement,
+ family_type: str = tags.GEDCOM_TAG_FAMILY_SPOUSE) -> List[FamilyElement]:
+ """Return family elements listed for an individual.
+
+ Optional argument `family_type` can be used to return specific subsets:
- 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.
+ `tags.GEDCOM_TAG_FAMILY_SPOUSE`: Default, families where the individual is a spouse.
- :type individual: IndividualElement
- :type family_type: str
- :rtype: list of FamilyElement
+ `tags.GEDCOM_TAG_FAMILY_CHILD`: Families where the individual is a child.
"""
if not isinstance(individual, IndividualElement):
raise NotAnActualIndividualError(
- "Operation only valid for elements with %s tag" % gedcom.tags.GEDCOM_TAG_INDIVIDUAL
+ "Operation only valid for elements with %s tag" % tags.GEDCOM_TAG_INDIVIDUAL
)
families = []
@@ -417,19 +430,19 @@
Module gedcom.parser
return families
- def get_ancestors(self, individual, ancestor_type="ALL"):
- """Return elements corresponding to ancestors of an individual
+ def get_ancestors(self, individual: IndividualElement,
+ ancestor_type: str = "ALL") -> List[Element]:
+ """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.
+ Optional argument `ancestor_type` can be used to return specific subsets:
- :type individual: IndividualElement
- :type ancestor_type: str
- :rtype: list of Element
+ "ALL": Default, returns all ancestors.
+
+ "NAT": Return only natural (genetic) ancestors.
"""
if not isinstance(individual, IndividualElement):
raise NotAnActualIndividualError(
- "Operation only valid for elements with %s tag" % gedcom.tags.GEDCOM_TAG_INDIVIDUAL
+ "Operation only valid for elements with %s tag" % tags.GEDCOM_TAG_INDIVIDUAL
)
parents = self.get_parents(individual, ancestor_type)
@@ -441,49 +454,53 @@
Module gedcom.parser
return ancestors
- def get_parents(self, individual, parent_type="ALL"):
- """Return elements corresponding to parents of an individual
+ def get_parents(self, individual: IndividualElement,
+ parent_type: str = "ALL") -> List[IndividualElement]:
+ """Return elements corresponding to parents of an individual.
+
+ Optional argument `parent_type` can be used to return specific subsets:
- Optional parent_type. Default "ALL" returns all parents. "NAT" can be
- used to specify only natural (genetic) parents.
+ "ALL": Default, returns all parents.
- :type individual: IndividualElement
- :type parent_type: str
- :rtype: list of IndividualElement
+ "NAT": Return only natural (genetic) parents.
"""
if not isinstance(individual, IndividualElement):
raise NotAnActualIndividualError(
- "Operation only valid for elements with %s tag" % gedcom.tags.GEDCOM_TAG_INDIVIDUAL
+ "Operation only valid for elements with %s tag" % tags.GEDCOM_TAG_INDIVIDUAL
)
parents = []
- families = self.get_families(individual, gedcom.tags.GEDCOM_TAG_FAMILY_CHILD)
+ families = self.get_families(individual, 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 \
+ if family_member.get_tag() == 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)
+ if child.get_tag() == tags.GEDCOM_PROGRAM_DEFINED_TAG_MREL:
+ parents += self.get_family_members(family,
+ tags.GEDCOM_TAG_WIFE)
+ elif child.get_tag() == tags.GEDCOM_PROGRAM_DEFINED_TAG_FREL:
+ parents += self.get_family_members(family,
+ tags.GEDCOM_TAG_HUSBAND)
else:
parents += self.get_family_members(family, "PARENTS")
return parents
- def find_path_to_ancestor(self, descendant, ancestor, path=None):
- """Return path from descendant to ancestor
+ def find_path_to_ancestor(self, descendant: IndividualElement,
+ ancestor: IndividualElement, path: str = None):
+ """Return path from descendant to ancestor.
:rtype: object
"""
- if not isinstance(descendant, IndividualElement) and isinstance(ancestor, IndividualElement):
+ if not isinstance(descendant, IndividualElement) and isinstance(ancestor,
+ IndividualElement):
raise NotAnActualIndividualError(
- "Operation only valid for elements with %s tag." % gedcom.tags.GEDCOM_TAG_INDIVIDUAL
+ "Operation only valid for elements with %s tag." % tags.GEDCOM_TAG_INDIVIDUAL
)
if not path:
@@ -491,33 +508,34 @@
Module gedcom.parser
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
+
+ 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
- def get_family_members(self, family, members_type=FAMILY_MEMBERS_TYPE_ALL):
- """Return array of family members: individual, spouse, and children
+ def get_family_members(self, family: FamilyElement,
+ members_type: str = FAMILY_MEMBERS_TYPE_ALL) -> List[IndividualElement]:
+ """Return array of family members: individual, spouse, and children.
Optional argument `members_type` can be used to return specific subsets:
"FAMILY_MEMBERS_TYPE_ALL": Default, return all members of the family
+
"FAMILY_MEMBERS_TYPE_PARENTS": Return individuals with "HUSB" and "WIFE" tags (parents)
+
"FAMILY_MEMBERS_TYPE_HUSBAND": Return individuals with "HUSB" tags (father)
+
"FAMILY_MEMBERS_TYPE_WIFE": Return individuals with "WIFE" tags (mother)
- "FAMILY_MEMBERS_TYPE_CHILDREN": Return individuals with "CHIL" tags (children)
- :type family: FamilyElement
- :type members_type: str
- :rtype: list of IndividualElement
+ "FAMILY_MEMBERS_TYPE_CHILDREN": Return individuals with "CHIL" tags (children)
"""
if not isinstance(family, FamilyElement):
raise NotAnActualFamilyError(
- "Operation only valid for element with %s tag." % gedcom.tags.GEDCOM_TAG_FAMILY
+ "Operation only valid for element with %s tag." % tags.GEDCOM_TAG_FAMILY
)
family_members = []
@@ -525,19 +543,19 @@
Module gedcom.parser
for child_element in family.get_child_elements():
# Default is ALL
- is_family = (child_element.get_tag() == gedcom.tags.GEDCOM_TAG_HUSBAND
- or child_element.get_tag() == gedcom.tags.GEDCOM_TAG_WIFE
- or child_element.get_tag() == gedcom.tags.GEDCOM_TAG_CHILD)
+ is_family = (child_element.get_tag() == tags.GEDCOM_TAG_HUSBAND
+ or child_element.get_tag() == tags.GEDCOM_TAG_WIFE
+ or child_element.get_tag() == tags.GEDCOM_TAG_CHILD)
if members_type == FAMILY_MEMBERS_TYPE_PARENTS:
- is_family = (child_element.get_tag() == gedcom.tags.GEDCOM_TAG_HUSBAND
- or child_element.get_tag() == gedcom.tags.GEDCOM_TAG_WIFE)
+ is_family = (child_element.get_tag() == tags.GEDCOM_TAG_HUSBAND
+ or child_element.get_tag() == tags.GEDCOM_TAG_WIFE)
elif members_type == FAMILY_MEMBERS_TYPE_HUSBAND:
- is_family = child_element.get_tag() == gedcom.tags.GEDCOM_TAG_HUSBAND
+ is_family = child_element.get_tag() == tags.GEDCOM_TAG_HUSBAND
elif members_type == FAMILY_MEMBERS_TYPE_WIFE:
- is_family = child_element.get_tag() == gedcom.tags.GEDCOM_TAG_WIFE
+ is_family = child_element.get_tag() == tags.GEDCOM_TAG_WIFE
elif members_type == FAMILY_MEMBERS_TYPE_CHILDREN:
- is_family = child_element.get_tag() == gedcom.tags.GEDCOM_TAG_CHILD
+ is_family = child_element.get_tag() == tags.GEDCOM_TAG_CHILD
if is_family and child_element.get_value() in element_dictionary:
family_members.append(element_dictionary[child_element.get_value()])
@@ -546,9 +564,9 @@
Module gedcom.parser
# Other methods
- def to_gedcom_string(self, recursive=False):
- """Formats all elements and optionally all of the sub-elements into a GEDCOM string
- :type recursive: bool
+ def to_gedcom_string(self, recursive: bool = False) -> str:
+ """Formats all elements and optionally all of the sub-elements into a
+ GEDCOM string.
"""
is_gte_python_3 = version_info[0] >= 3
output = '' if is_gte_python_3 else b''
@@ -562,14 +580,11 @@
Module gedcom.parser
return output
def print_gedcom(self):
- """Write GEDCOM data to stdout"""
- from sys import stdout
+ """Write GEDCOM data to stdout."""
self.save_gedcom(stdout)
- def save_gedcom(self, open_file, recursive=True):
- """Save GEDCOM data to a file
- :type open_file: file
- :type recursive: bool
+ def save_gedcom(self, open_file: IO, recursive: bool = True):
+ """Save GEDCOM data to a file.
"""
open_file.write(self.to_gedcom_string(recursive))
@@ -583,45 +598,28 @@
Module gedcom.parser
Classes
-
-class GedcomFormatViolationError
-(...)
-
-
-
Common base class for all non-exit exceptions.
-
-
-Expand source code
-
-
class GedcomFormatViolationError(Exception):
- pass
class Parser(object):
- """Parses and manipulates GEDCOM 5.5 format data
+
class Parser():
+ """Parses and manipulates GEDCOM formatted data.
- For documentation of the GEDCOM 5.5 format, see: http://homepages.rootsweb.ancestry.com/~pmcbride/gedcom/55gctoc.htm
+ For documentation of the different GEDCOM standards see the
+ links defined in `gedcom.standards`
This parser reads and parses a GEDCOM file.
@@ -637,35 +635,36 @@
Ancestors
self.__root_element = RootElement()
def invalidate_cache(self):
- """Empties the element list and dictionary to cause `gedcom.parser.Parser.get_element_list()`
- and `gedcom.parser.Parser.get_element_dictionary()` to return updated data.
+ """Empties the element list and dictionary to cause
+ `gedcom.parser.Parser.get_element_list()` and
+ `gedcom.parser.Parser.get_element_dictionary()` to return updated data.
The update gets deferred until each of the methods actually gets called.
"""
self.__element_list = []
self.__element_dictionary = {}
- def get_element_list(self):
- """Returns a list containing all elements from within the GEDCOM file
+ def get_element_list(self) -> List[Element]:
+ """Returns a list containing all elements from within the GEDCOM file.
By default elements are in the same order as they appeared in the file.
This list gets generated on-the-fly, but gets cached. If the database
- was modified, you should call `gedcom.parser.Parser.invalidate_cache()` once to let this
- method return updated data.
+ was modified, you should call `gedcom.parser.Parser.invalidate_cache()` once
+ to let this method return updated data.
- Consider using `gedcom.parser.Parser.get_root_element()` or `gedcom.parser.Parser.get_root_child_elements()` to access
+ Consider using `gedcom.parser.Parser.get_root_element()` or
+ `gedcom.parser.Parser.get_root_child_elements()` to access
the hierarchical GEDCOM tree, unless you rarely modify the database.
-
- :rtype: list of Element
"""
if not self.__element_list:
for element in self.get_root_child_elements():
self.__build_list(element, self.__element_list)
return self.__element_list
- def get_element_dictionary(self):
- """Returns a dictionary containing all elements, identified by a pointer, from within the GEDCOM file
+ def get_element_dictionary(self) -> dict:
+ """Returns a dictionary containing all elements, identified by a pointer,
+ from within the GEDCOM file.
Only elements identified by a pointer are listed in the dictionary.
The keys for the dictionary are the pointers.
@@ -673,46 +672,51 @@
Ancestors
This dictionary gets generated on-the-fly, but gets cached. If the
database was modified, you should call `invalidate_cache()` once to let
this method return updated data.
-
- :rtype: dict of Element
"""
if not self.__element_dictionary:
self.__element_dictionary = {
- element.get_pointer(): element for element in self.get_root_child_elements() if element.get_pointer()
+ element.get_pointer():
+ element for element in self.get_root_child_elements() if element.get_pointer()
}
return self.__element_dictionary
- def get_root_element(self):
- """Returns a virtual root element containing all logical records as children
+ def get_root_element(self) -> RootElement:
+ """Returns a virtual root element containing all logical records as children.
When printed, this element converts to an empty string.
-
- :rtype: RootElement
"""
return self.__root_element
- def get_root_child_elements(self):
- """Returns a list of logical records in the GEDCOM file
+ def get_root_child_elements(self) -> List[Element]:
+ """Returns a list of logical records in the GEDCOM file.
By default, elements are in the same order as they appeared in the file.
-
- :rtype: list of Element
"""
return self.get_root_element().get_child_elements()
- def parse_file(self, file_path, strict=True):
- """Opens and parses a file, from the given file path, as GEDCOM 5.5 formatted data
- :type file_path: str
- :type strict: bool
+ def parse_file(self, file_path: str, strict: bool = True):
+ """Opens and parses a file, from the given file path, as GEDCOM formatted data.
"""
- with open(file_path, 'rb') as gedcom_stream:
+ codec = get_encoding(file_path)
+ real_version, reported_version, reported_format = get_version(file_path, codec)
+
+ if reported_version == '5.5.5':
+ errmsg = "This parser does not properly support the GEDCOM " + reported_version + \
+ " standard at this time\nSee: {0}".format(standards.GEDCOM_5_5_5)
+ raise GedcomVersionUnsupportedError(errmsg)
+
+ if reported_format not in ['LINEAGE-LINKED', 'LINEAGE_LINKED',
+ 'LINAGE-LINKED', 'Lineage - Linked']:
+ errmsg = "This parser does not recognize the GEDCOM format " + reported_format + \
+ " at this time\nSee: {0}".format(standards.GEDCOM_5_5_5)
+ raise GedcomFormatUnsupportedError(errmsg)
+
+ with open(file_path, 'r', encoding=codec) as gedcom_stream:
self.parse(gedcom_stream, strict)
- def parse(self, gedcom_stream, strict=True):
- """Parses a stream, or an array of lines, as GEDCOM 5.5 formatted data
- :type gedcom_stream: a file stream, or str array of lines with new line at the end
- :type strict: bool
+ def parse(self, gedcom_stream: IO, strict: bool = True):
+ """Parses a stream, or an array of lines, as GEDCOM formatted data.
"""
self.invalidate_cache()
self.__root_element = RootElement()
@@ -721,24 +725,18 @@
Ancestors
last_element = self.get_root_element()
for line in gedcom_stream:
- last_element = self.__parse_line(line_number, line.decode('utf-8-sig'), last_element, strict)
+ last_element = self.__parse_line(line_number, line, last_element, strict)
line_number += 1
# Private methods
@staticmethod
- def __parse_line(line_number, line, last_element, strict=True):
- """Parse a line from a GEDCOM 5.5 formatted document
+ def __parse_line(line_number: int, line: str, last_element: Element,
+ strict: bool = True) -> Element:
+ """Parse a line from a GEDCOM 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.
@@ -757,43 +755,43 @@
Ancestors
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
+ 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:%s> of document violates GEDCOM format 5.5" % (line_number, line)
- + "\nSee: https://chronoplexsoftware.com/gedcomvalidator/gedcom/gedcom-5.5.pdf")
- raise GedcomFormatViolationError(error_message)
+ errmsg = ERROR_TEMPLATE.format(line_number, line, '5.5.1', standards.GEDCOM_5_5_1)
+ raise GedcomFormatViolationError(errmsg)
+
+ # 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 - 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
+ # 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 not in [tags.GEDCOM_TAG_CONTINUED, tags.GEDCOM_TAG_CONCATENATION]:
+ # Increment level and change this line to a CONC
+ level += 1
+ tag = tags.GEDCOM_TAG_CONCATENATION
else:
line_parts = regex_match.groups()
@@ -805,20 +803,14 @@
Ancestors
# 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)
+ errmsg = "Line {0} of document violates GEDCOM format 5.5.1\n".format(line_number) + \
+ "Lines must be no more than one level higher than previous line.\n" + \
+ "See: {0}".format(standards.GEDCOM_5_5_1)
+ raise GedcomFormatViolationError(errmsg)
# 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)
+ if tag in RECORD_ELEMENTS:
+ element = RECORD_ELEMENTS[tag](level, pointer, tag, value, crlf, multi_line=False)
else:
element = Element(level, pointer, tag, value, crlf, multi_line=False)
@@ -833,10 +825,8 @@
Ancestors
return element
- def __build_list(self, element, element_list):
- """Recursively add elements to a list containing elements
- :type element: Element
- :type element_list: list of Element
+ def __build_list(self, element: Element, element_list: List[Element]):
+ """Recursively add elements to a list containing elements.
"""
element_list.append(element)
for child in element.get_child_elements():
@@ -844,81 +834,74 @@
Ancestors
# Methods for analyzing individuals and relationships between individuals
- 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
+ def get_marriages(self, individual: IndividualElement) -> Tuple[str, str]:
+ """Returns a list of marriages of an individual formatted as a tuple:
+ (`str` date, `str` place)
"""
marriages = []
if not isinstance(individual, IndividualElement):
raise NotAnActualIndividualError(
- "Operation only valid for elements with %s tag" % gedcom.tags.GEDCOM_TAG_INDIVIDUAL
+ "Operation only valid for elements with %s tag" % tags.GEDCOM_TAG_INDIVIDUAL
)
# Get and analyze families where individual is spouse.
- families = self.get_families(individual, gedcom.tags.GEDCOM_TAG_FAMILY_SPOUSE)
+ families = self.get_families(individual, 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:
+ if family_data.get_tag() == 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:
+ if marriage_data.get_tag() == tags.GEDCOM_TAG_DATE:
date = marriage_data.get_value()
- if marriage_data.get_tag() == gedcom.tags.GEDCOM_TAG_PLACE:
+ if marriage_data.get_tag() == tags.GEDCOM_TAG_PLACE:
place = marriage_data.get_value()
marriages.append((date, place))
return marriages
- def get_marriage_years(self, individual):
- """Returns a list of marriage years (as integers) for an individual
- :type individual: IndividualElement
- :rtype: list of int
+ def get_marriage_years(self, individual: IndividualElement) -> List[int]:
+ """Returns a list of marriage years for an individual.
"""
dates = []
if not isinstance(individual, IndividualElement):
raise NotAnActualIndividualError(
- "Operation only valid for elements with %s tag" % gedcom.tags.GEDCOM_TAG_INDIVIDUAL
+ "Operation only valid for elements with %s tag" % tags.GEDCOM_TAG_INDIVIDUAL
)
# Get and analyze families where individual is spouse.
- families = self.get_families(individual, gedcom.tags.GEDCOM_TAG_FAMILY_SPOUSE)
+ families = self.get_families(individual, 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]
+ if child.get_tag() == tags.GEDCOM_TAG_MARRIAGE:
+ for gchild in child.get_child_elements():
+ if gchild.get_tag() == tags.GEDCOM_TAG_DATE:
+ date = gchild.get_value().split()[-1]
try:
dates.append(int(date))
except ValueError:
pass
return dates
- 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
+ def marriage_year_match(self, individual: IndividualElement, year: int) -> bool:
+ """Checks if one of the marriage years of an individual matches the supplied year.
+ Year is an integer.
"""
if not isinstance(individual, IndividualElement):
raise NotAnActualIndividualError(
- "Operation only valid for elements with %s tag" % gedcom.tags.GEDCOM_TAG_INDIVIDUAL
+ "Operation only valid for elements with %s tag" % 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
+ def marriage_range_match(self, individual: IndividualElement,
+ from_year: int, to_year: int) -> bool:
+ """Check if one of the marriage years of an individual is in a given range.
+ Years are integers.
"""
if not isinstance(individual, IndividualElement):
raise NotAnActualIndividualError(
- "Operation only valid for elements with %s tag" % gedcom.tags.GEDCOM_TAG_INDIVIDUAL
+ "Operation only valid for elements with %s tag" % tags.GEDCOM_TAG_INDIVIDUAL
)
years = self.get_marriage_years(individual)
@@ -927,20 +910,19 @@
Ancestors
return True
return False
- def get_families(self, individual, family_type=gedcom.tags.GEDCOM_TAG_FAMILY_SPOUSE):
- """Return family elements listed for an individual
+ def get_families(self, individual: IndividualElement,
+ family_type: str = tags.GEDCOM_TAG_FAMILY_SPOUSE) -> List[FamilyElement]:
+ """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.
+ Optional argument `family_type` can be used to return specific subsets:
- :type individual: IndividualElement
- :type family_type: str
- :rtype: list of FamilyElement
+ `tags.GEDCOM_TAG_FAMILY_SPOUSE`: Default, families where the individual is a spouse.
+
+ `tags.GEDCOM_TAG_FAMILY_CHILD`: Families where the individual is a child.
"""
if not isinstance(individual, IndividualElement):
raise NotAnActualIndividualError(
- "Operation only valid for elements with %s tag" % gedcom.tags.GEDCOM_TAG_INDIVIDUAL
+ "Operation only valid for elements with %s tag" % tags.GEDCOM_TAG_INDIVIDUAL
)
families = []
@@ -955,19 +937,19 @@
Ancestors
return families
- def get_ancestors(self, individual, ancestor_type="ALL"):
- """Return elements corresponding to ancestors of an individual
+ def get_ancestors(self, individual: IndividualElement,
+ ancestor_type: str = "ALL") -> List[Element]:
+ """Return elements corresponding to ancestors of an individual.
+
+ Optional argument `ancestor_type` can be used to return specific subsets:
- Optional `ancestor_type`. Default "ALL" returns all ancestors, "NAT" can be
- used to specify only natural (genetic) ancestors.
+ "ALL": Default, returns all ancestors.
- :type individual: IndividualElement
- :type ancestor_type: str
- :rtype: list of Element
+ "NAT": Return only natural (genetic) ancestors.
"""
if not isinstance(individual, IndividualElement):
raise NotAnActualIndividualError(
- "Operation only valid for elements with %s tag" % gedcom.tags.GEDCOM_TAG_INDIVIDUAL
+ "Operation only valid for elements with %s tag" % tags.GEDCOM_TAG_INDIVIDUAL
)
parents = self.get_parents(individual, ancestor_type)
@@ -979,49 +961,53 @@
Ancestors
return ancestors
- def get_parents(self, individual, parent_type="ALL"):
- """Return elements corresponding to parents of an individual
+ def get_parents(self, individual: IndividualElement,
+ parent_type: str = "ALL") -> List[IndividualElement]:
+ """Return elements corresponding to parents of an individual.
+
+ Optional argument `parent_type` can be used to return specific subsets:
- Optional parent_type. Default "ALL" returns all parents. "NAT" can be
- used to specify only natural (genetic) parents.
+ "ALL": Default, returns all parents.
- :type individual: IndividualElement
- :type parent_type: str
- :rtype: list of IndividualElement
+ "NAT": Return only natural (genetic) parents.
"""
if not isinstance(individual, IndividualElement):
raise NotAnActualIndividualError(
- "Operation only valid for elements with %s tag" % gedcom.tags.GEDCOM_TAG_INDIVIDUAL
+ "Operation only valid for elements with %s tag" % tags.GEDCOM_TAG_INDIVIDUAL
)
parents = []
- families = self.get_families(individual, gedcom.tags.GEDCOM_TAG_FAMILY_CHILD)
+ families = self.get_families(individual, 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 \
+ if family_member.get_tag() == 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)
+ if child.get_tag() == tags.GEDCOM_PROGRAM_DEFINED_TAG_MREL:
+ parents += self.get_family_members(family,
+ tags.GEDCOM_TAG_WIFE)
+ elif child.get_tag() == tags.GEDCOM_PROGRAM_DEFINED_TAG_FREL:
+ parents += self.get_family_members(family,
+ tags.GEDCOM_TAG_HUSBAND)
else:
parents += self.get_family_members(family, "PARENTS")
return parents
- def find_path_to_ancestor(self, descendant, ancestor, path=None):
- """Return path from descendant to ancestor
+ def find_path_to_ancestor(self, descendant: IndividualElement,
+ ancestor: IndividualElement, path: str = None):
+ """Return path from descendant to ancestor.
:rtype: object
"""
- if not isinstance(descendant, IndividualElement) and isinstance(ancestor, IndividualElement):
+ if not isinstance(descendant, IndividualElement) and isinstance(ancestor,
+ IndividualElement):
raise NotAnActualIndividualError(
- "Operation only valid for elements with %s tag." % gedcom.tags.GEDCOM_TAG_INDIVIDUAL
+ "Operation only valid for elements with %s tag." % tags.GEDCOM_TAG_INDIVIDUAL
)
if not path:
@@ -1029,33 +1015,34 @@
Ancestors
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
+
+ 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
- def get_family_members(self, family, members_type=FAMILY_MEMBERS_TYPE_ALL):
- """Return array of family members: individual, spouse, and children
+ def get_family_members(self, family: FamilyElement,
+ members_type: str = FAMILY_MEMBERS_TYPE_ALL) -> List[IndividualElement]:
+ """Return array of family members: individual, spouse, and children.
Optional argument `members_type` can be used to return specific subsets:
"FAMILY_MEMBERS_TYPE_ALL": Default, return all members of the family
+
"FAMILY_MEMBERS_TYPE_PARENTS": Return individuals with "HUSB" and "WIFE" tags (parents)
+
"FAMILY_MEMBERS_TYPE_HUSBAND": Return individuals with "HUSB" tags (father)
+
"FAMILY_MEMBERS_TYPE_WIFE": Return individuals with "WIFE" tags (mother)
- "FAMILY_MEMBERS_TYPE_CHILDREN": Return individuals with "CHIL" tags (children)
- :type family: FamilyElement
- :type members_type: str
- :rtype: list of IndividualElement
+ "FAMILY_MEMBERS_TYPE_CHILDREN": Return individuals with "CHIL" tags (children)
"""
if not isinstance(family, FamilyElement):
raise NotAnActualFamilyError(
- "Operation only valid for element with %s tag." % gedcom.tags.GEDCOM_TAG_FAMILY
+ "Operation only valid for element with %s tag." % tags.GEDCOM_TAG_FAMILY
)
family_members = []
@@ -1063,19 +1050,19 @@
Ancestors
for child_element in family.get_child_elements():
# Default is ALL
- is_family = (child_element.get_tag() == gedcom.tags.GEDCOM_TAG_HUSBAND
- or child_element.get_tag() == gedcom.tags.GEDCOM_TAG_WIFE
- or child_element.get_tag() == gedcom.tags.GEDCOM_TAG_CHILD)
+ is_family = (child_element.get_tag() == tags.GEDCOM_TAG_HUSBAND
+ or child_element.get_tag() == tags.GEDCOM_TAG_WIFE
+ or child_element.get_tag() == tags.GEDCOM_TAG_CHILD)
if members_type == FAMILY_MEMBERS_TYPE_PARENTS:
- is_family = (child_element.get_tag() == gedcom.tags.GEDCOM_TAG_HUSBAND
- or child_element.get_tag() == gedcom.tags.GEDCOM_TAG_WIFE)
+ is_family = (child_element.get_tag() == tags.GEDCOM_TAG_HUSBAND
+ or child_element.get_tag() == tags.GEDCOM_TAG_WIFE)
elif members_type == FAMILY_MEMBERS_TYPE_HUSBAND:
- is_family = child_element.get_tag() == gedcom.tags.GEDCOM_TAG_HUSBAND
+ is_family = child_element.get_tag() == tags.GEDCOM_TAG_HUSBAND
elif members_type == FAMILY_MEMBERS_TYPE_WIFE:
- is_family = child_element.get_tag() == gedcom.tags.GEDCOM_TAG_WIFE
+ is_family = child_element.get_tag() == tags.GEDCOM_TAG_WIFE
elif members_type == FAMILY_MEMBERS_TYPE_CHILDREN:
- is_family = child_element.get_tag() == gedcom.tags.GEDCOM_TAG_CHILD
+ is_family = child_element.get_tag() == tags.GEDCOM_TAG_CHILD
if is_family and child_element.get_value() in element_dictionary:
family_members.append(element_dictionary[child_element.get_value()])
@@ -1084,9 +1071,9 @@
Ancestors
# Other methods
- def to_gedcom_string(self, recursive=False):
- """Formats all elements and optionally all of the sub-elements into a GEDCOM string
- :type recursive: bool
+ def to_gedcom_string(self, recursive: bool = False) -> str:
+ """Formats all elements and optionally all of the sub-elements into a
+ GEDCOM string.
"""
is_gte_python_3 = version_info[0] >= 3
output = '' if is_gte_python_3 else b''
@@ -1100,36 +1087,39 @@
Ancestors
return output
def print_gedcom(self):
- """Write GEDCOM data to stdout"""
- from sys import stdout
+ """Write GEDCOM data to stdout."""
self.save_gedcom(stdout)
- def save_gedcom(self, open_file, recursive=True):
- """Save GEDCOM data to a file
- :type open_file: file
- :type recursive: bool
+ def save_gedcom(self, open_file: IO, recursive: bool = True):
+ """Save GEDCOM data to a file.
"""
open_file.write(self.to_gedcom_string(recursive))
Return path from descendant to ancestor
-:rtype: object
+
Return path from descendant to ancestor.
+:rtype: object
Expand source code
-
def find_path_to_ancestor(self, descendant, ancestor, path=None):
- """Return path from descendant to ancestor
+
def find_path_to_ancestor(self, descendant: IndividualElement,
+ ancestor: IndividualElement, path: str = None):
+ """Return path from descendant to ancestor.
:rtype: object
"""
- if not isinstance(descendant, IndividualElement) and isinstance(ancestor, IndividualElement):
+ if not isinstance(descendant, IndividualElement) and isinstance(ancestor,
+ IndividualElement):
raise NotAnActualIndividualError(
- "Operation only valid for elements with %s tag." % gedcom.tags.GEDCOM_TAG_INDIVIDUAL
+ "Operation only valid for elements with %s tag." % tags.GEDCOM_TAG_INDIVIDUAL
)
if not path:
@@ -1137,43 +1127,41 @@
Methods
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
+
+ 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
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
+
Return elements corresponding to ancestors of an individual.
+
Optional argument ancestor_type can be used to return specific subsets:
+
"ALL": Default, returns all ancestors.
+
"NAT": Return only natural (genetic) ancestors.
Expand source code
-
def get_ancestors(self, individual, ancestor_type="ALL"):
- """Return elements corresponding to ancestors of an individual
+
def get_ancestors(self, individual: IndividualElement,
+ ancestor_type: str = "ALL") -> List[Element]:
+ """Return elements corresponding to ancestors of an individual.
+
+ Optional argument `ancestor_type` can be used to return specific subsets:
- Optional `ancestor_type`. Default "ALL" returns all ancestors, "NAT" can be
- used to specify only natural (genetic) ancestors.
+ "ALL": Default, returns all ancestors.
- :type individual: IndividualElement
- :type ancestor_type: str
- :rtype: list of Element
+ "NAT": Return only natural (genetic) ancestors.
"""
if not isinstance(individual, IndividualElement):
raise NotAnActualIndividualError(
- "Operation only valid for elements with %s tag" % gedcom.tags.GEDCOM_TAG_INDIVIDUAL
+ "Operation only valid for elements with %s tag" % tags.GEDCOM_TAG_INDIVIDUAL
)
parents = self.get_parents(individual, ancestor_type)
@@ -1187,22 +1175,23 @@
Returns a dictionary containing all elements, identified by a pointer, from within the GEDCOM file
+
Returns a dictionary containing all elements, identified by a pointer,
+from within the GEDCOM file.
Only elements identified by a pointer are listed in the dictionary.
The keys for the dictionary are the pointers.
This dictionary gets generated on-the-fly, but gets cached. If the
database was modified, you should call invalidate_cache() once to let
-this method return updated data.
-
:rtype: dict of Element
+this method return updated data.
Expand source code
-
def get_element_dictionary(self):
- """Returns a dictionary containing all elements, identified by a pointer, from within the GEDCOM file
+
def get_element_dictionary(self) -> dict:
+ """Returns a dictionary containing all elements, identified by a pointer,
+ from within the GEDCOM file.
Only elements identified by a pointer are listed in the dictionary.
The keys for the dictionary are the pointers.
@@ -1210,46 +1199,44 @@
Methods
This dictionary gets generated on-the-fly, but gets cached. If the
database was modified, you should call `invalidate_cache()` once to let
this method return updated data.
-
- :rtype: dict of Element
"""
if not self.__element_dictionary:
self.__element_dictionary = {
- element.get_pointer(): element for element in self.get_root_child_elements() if element.get_pointer()
+ element.get_pointer():
+ element for element in self.get_root_child_elements() if element.get_pointer()
}
return self.__element_dictionary
Returns a list containing all elements from within the GEDCOM file
+
Returns a list containing all elements from within the GEDCOM file.
By default elements are in the same order as they appeared in the file.
This list gets generated on-the-fly, but gets cached. If the database
-was modified, you should call Parser.invalidate_cache() once to let this
-method return updated data.
def get_element_list(self):
- """Returns a list containing all elements from within the GEDCOM file
+
def get_element_list(self) -> List[Element]:
+ """Returns a list containing all elements from within the GEDCOM file.
By default elements are in the same order as they appeared in the file.
This list gets generated on-the-fly, but gets cached. If the database
- was modified, you should call `gedcom.parser.Parser.invalidate_cache()` once to let this
- method return updated data.
+ was modified, you should call `gedcom.parser.Parser.invalidate_cache()` once
+ to let this method return updated data.
- Consider using `gedcom.parser.Parser.get_root_element()` or `gedcom.parser.Parser.get_root_child_elements()` to access
+ Consider using `gedcom.parser.Parser.get_root_element()` or
+ `gedcom.parser.Parser.get_root_child_elements()` to access
the hierarchical GEDCOM tree, unless you rarely modify the database.
-
- :rtype: list of Element
"""
if not self.__element_list:
for element in self.get_root_child_elements():
@@ -1258,34 +1245,30 @@
:type individual: IndividualElement
-:type family_type: str
-:rtype: list of FamilyElement
+
Return family elements listed for an individual.
+
Optional argument family_type can be used to return specific subsets:
+
tags.GEDCOM_TAG_FAMILY_SPOUSE: Default, families where the individual is a spouse.
+
tags.GEDCOM_TAG_FAMILY_CHILD: Families where the individual is a child.
Expand source code
-
def get_families(self, individual, family_type=gedcom.tags.GEDCOM_TAG_FAMILY_SPOUSE):
- """Return family elements listed for an individual
+
def get_families(self, individual: IndividualElement,
+ family_type: str = tags.GEDCOM_TAG_FAMILY_SPOUSE) -> List[FamilyElement]:
+ """Return family elements listed for an individual.
+
+ Optional argument `family_type` can be used to return specific subsets:
- 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.
+ `tags.GEDCOM_TAG_FAMILY_SPOUSE`: Default, families where the individual is a spouse.
- :type individual: IndividualElement
- :type family_type: str
- :rtype: list of FamilyElement
+ `tags.GEDCOM_TAG_FAMILY_CHILD`: Families where the individual is a child.
"""
if not isinstance(individual, IndividualElement):
raise NotAnActualIndividualError(
- "Operation only valid for elements with %s tag" % gedcom.tags.GEDCOM_TAG_INDIVIDUAL
+ "Operation only valid for elements with %s tag" % tags.GEDCOM_TAG_INDIVIDUAL
)
families = []
@@ -1302,41 +1285,39 @@
Return array of family members: individual, spouse, and children
+
Return array of family members: individual, spouse, and children.
Optional argument members_type can be used to return specific subsets:
-
"FAMILY_MEMBERS_TYPE_ALL": Default, return all members of the family
-"FAMILY_MEMBERS_TYPE_PARENTS": Return individuals with "HUSB" and "WIFE" tags (parents)
-"FAMILY_MEMBERS_TYPE_HUSBAND": Return individuals with "HUSB" tags (father)
-"FAMILY_MEMBERS_TYPE_WIFE": Return individuals with "WIFE" tags (mother)
-"FAMILY_MEMBERS_TYPE_CHILDREN": Return individuals with "CHIL" tags (children)
-
:type family: FamilyElement
-:type members_type: str
-:rtype: list of IndividualElement
+
"FAMILY_MEMBERS_TYPE_ALL": Default, return all members of the family
+
"FAMILY_MEMBERS_TYPE_PARENTS": Return individuals with "HUSB" and "WIFE" tags (parents)
+
"FAMILY_MEMBERS_TYPE_HUSBAND": Return individuals with "HUSB" tags (father)
+
"FAMILY_MEMBERS_TYPE_WIFE": Return individuals with "WIFE" tags (mother)
+
"FAMILY_MEMBERS_TYPE_CHILDREN": Return individuals with "CHIL" tags (children)
Expand source code
-
def get_family_members(self, family, members_type=FAMILY_MEMBERS_TYPE_ALL):
- """Return array of family members: individual, spouse, and children
+
def get_family_members(self, family: FamilyElement,
+ members_type: str = FAMILY_MEMBERS_TYPE_ALL) -> List[IndividualElement]:
+ """Return array of family members: individual, spouse, and children.
Optional argument `members_type` can be used to return specific subsets:
"FAMILY_MEMBERS_TYPE_ALL": Default, return all members of the family
+
"FAMILY_MEMBERS_TYPE_PARENTS": Return individuals with "HUSB" and "WIFE" tags (parents)
+
"FAMILY_MEMBERS_TYPE_HUSBAND": Return individuals with "HUSB" tags (father)
+
"FAMILY_MEMBERS_TYPE_WIFE": Return individuals with "WIFE" tags (mother)
- "FAMILY_MEMBERS_TYPE_CHILDREN": Return individuals with "CHIL" tags (children)
- :type family: FamilyElement
- :type members_type: str
- :rtype: list of IndividualElement
+ "FAMILY_MEMBERS_TYPE_CHILDREN": Return individuals with "CHIL" tags (children)
"""
if not isinstance(family, FamilyElement):
raise NotAnActualFamilyError(
- "Operation only valid for element with %s tag." % gedcom.tags.GEDCOM_TAG_FAMILY
+ "Operation only valid for element with %s tag." % tags.GEDCOM_TAG_FAMILY
)
family_members = []
@@ -1344,19 +1325,19 @@
Methods
for child_element in family.get_child_elements():
# Default is ALL
- is_family = (child_element.get_tag() == gedcom.tags.GEDCOM_TAG_HUSBAND
- or child_element.get_tag() == gedcom.tags.GEDCOM_TAG_WIFE
- or child_element.get_tag() == gedcom.tags.GEDCOM_TAG_CHILD)
+ is_family = (child_element.get_tag() == tags.GEDCOM_TAG_HUSBAND
+ or child_element.get_tag() == tags.GEDCOM_TAG_WIFE
+ or child_element.get_tag() == tags.GEDCOM_TAG_CHILD)
if members_type == FAMILY_MEMBERS_TYPE_PARENTS:
- is_family = (child_element.get_tag() == gedcom.tags.GEDCOM_TAG_HUSBAND
- or child_element.get_tag() == gedcom.tags.GEDCOM_TAG_WIFE)
+ is_family = (child_element.get_tag() == tags.GEDCOM_TAG_HUSBAND
+ or child_element.get_tag() == tags.GEDCOM_TAG_WIFE)
elif members_type == FAMILY_MEMBERS_TYPE_HUSBAND:
- is_family = child_element.get_tag() == gedcom.tags.GEDCOM_TAG_HUSBAND
+ is_family = child_element.get_tag() == tags.GEDCOM_TAG_HUSBAND
elif members_type == FAMILY_MEMBERS_TYPE_WIFE:
- is_family = child_element.get_tag() == gedcom.tags.GEDCOM_TAG_WIFE
+ is_family = child_element.get_tag() == tags.GEDCOM_TAG_WIFE
elif members_type == FAMILY_MEMBERS_TYPE_CHILDREN:
- is_family = child_element.get_tag() == gedcom.tags.GEDCOM_TAG_CHILD
+ is_family = child_element.get_tag() == tags.GEDCOM_TAG_CHILD
if is_family and child_element.get_value() in element_dictionary:
family_members.append(element_dictionary[child_element.get_value()])
@@ -1365,36 +1346,32 @@
Returns a list of marriage years (as integers) for an individual
-:type individual: IndividualElement
-:rtype: list of int
+
Returns a list of marriage years for an individual.
Expand source code
-
def get_marriage_years(self, individual):
- """Returns a list of marriage years (as integers) for an individual
- :type individual: IndividualElement
- :rtype: list of int
+
def get_marriage_years(self, individual: IndividualElement) -> List[int]:
+ """Returns a list of marriage years for an individual.
"""
dates = []
if not isinstance(individual, IndividualElement):
raise NotAnActualIndividualError(
- "Operation only valid for elements with %s tag" % gedcom.tags.GEDCOM_TAG_INDIVIDUAL
+ "Operation only valid for elements with %s tag" % tags.GEDCOM_TAG_INDIVIDUAL
)
# Get and analyze families where individual is spouse.
- families = self.get_families(individual, gedcom.tags.GEDCOM_TAG_FAMILY_SPOUSE)
+ families = self.get_families(individual, 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]
+ if child.get_tag() == tags.GEDCOM_TAG_MARRIAGE:
+ for gchild in child.get_child_elements():
+ if gchild.get_tag() == tags.GEDCOM_TAG_DATE:
+ date = gchild.get_value().split()[-1]
try:
dates.append(int(date))
except ValueError:
@@ -1403,87 +1380,85 @@
Returns a list of marriages of an individual formatted as a tuple (str date, str place)
-:type individual: IndividualElement
-:rtype: tuple
+
Returns a list of marriages of an individual formatted as a tuple:
+(str date, str place)
Expand source code
-
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
+
def get_marriages(self, individual: IndividualElement) -> Tuple[str, str]:
+ """Returns a list of marriages of an individual formatted as a tuple:
+ (`str` date, `str` place)
"""
marriages = []
if not isinstance(individual, IndividualElement):
raise NotAnActualIndividualError(
- "Operation only valid for elements with %s tag" % gedcom.tags.GEDCOM_TAG_INDIVIDUAL
+ "Operation only valid for elements with %s tag" % tags.GEDCOM_TAG_INDIVIDUAL
)
# Get and analyze families where individual is spouse.
- families = self.get_families(individual, gedcom.tags.GEDCOM_TAG_FAMILY_SPOUSE)
+ families = self.get_families(individual, 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:
+ if family_data.get_tag() == 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:
+ if marriage_data.get_tag() == tags.GEDCOM_TAG_DATE:
date = marriage_data.get_value()
- if marriage_data.get_tag() == gedcom.tags.GEDCOM_TAG_PLACE:
+ if marriage_data.get_tag() == tags.GEDCOM_TAG_PLACE:
place = marriage_data.get_value()
marriages.append((date, place))
return marriages
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
+
Return elements corresponding to parents of an individual.
+
Optional argument parent_type can be used to return specific subsets:
+
"ALL": Default, returns all parents.
+
"NAT": Return only natural (genetic) parents.
Expand source code
-
def get_parents(self, individual, parent_type="ALL"):
- """Return elements corresponding to parents of an individual
+
def get_parents(self, individual: IndividualElement,
+ parent_type: str = "ALL") -> List[IndividualElement]:
+ """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.
+ Optional argument `parent_type` can be used to return specific subsets:
- :type individual: IndividualElement
- :type parent_type: str
- :rtype: list of IndividualElement
+ "ALL": Default, returns all parents.
+
+ "NAT": Return only natural (genetic) parents.
"""
if not isinstance(individual, IndividualElement):
raise NotAnActualIndividualError(
- "Operation only valid for elements with %s tag" % gedcom.tags.GEDCOM_TAG_INDIVIDUAL
+ "Operation only valid for elements with %s tag" % tags.GEDCOM_TAG_INDIVIDUAL
)
parents = []
- families = self.get_families(individual, gedcom.tags.GEDCOM_TAG_FAMILY_CHILD)
+ families = self.get_families(individual, 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 \
+ if family_member.get_tag() == 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)
+ if child.get_tag() == tags.GEDCOM_PROGRAM_DEFINED_TAG_MREL:
+ parents += self.get_family_members(family,
+ tags.GEDCOM_TAG_WIFE)
+ elif child.get_tag() == tags.GEDCOM_PROGRAM_DEFINED_TAG_FREL:
+ parents += self.get_family_members(family,
+ tags.GEDCOM_TAG_HUSBAND)
else:
parents += self.get_family_members(family, "PARENTS")
@@ -1491,43 +1466,37 @@
Returns a list of logical records in the GEDCOM file
-
By default, elements are in the same order as they appeared in the file.
-
:rtype: list of Element
+
Returns a list of logical records in the GEDCOM file.
+
By default, elements are in the same order as they appeared in the file.
Expand source code
-
def get_root_child_elements(self):
- """Returns a list of logical records in the GEDCOM file
+
def get_root_child_elements(self) -> List[Element]:
+ """Returns a list of logical records in the GEDCOM file.
By default, elements are in the same order as they appeared in the file.
-
- :rtype: list of Element
"""
return self.get_root_element().get_child_elements()
Returns a virtual root element containing all logical records as children
-
When printed, this element converts to an empty string.
-
:rtype: RootElement
+
Returns a virtual root element containing all logical records as children.
+
When printed, this element converts to an empty string.
Expand source code
-
def get_root_element(self):
- """Returns a virtual root element containing all logical records as children
+
def get_root_element(self) -> RootElement:
+ """Returns a virtual root element containing all logical records as children.
When printed, this element converts to an empty string.
-
- :rtype: RootElement
"""
return self.__root_element
The update gets deferred until each of the methods actually gets called.
Expand source code
def invalidate_cache(self):
- """Empties the element list and dictionary to cause `gedcom.parser.Parser.get_element_list()`
- and `gedcom.parser.Parser.get_element_dictionary()` to return updated data.
+ """Empties the element list and dictionary to cause
+ `gedcom.parser.Parser.get_element_list()` and
+ `gedcom.parser.Parser.get_element_dictionary()` to return updated data.
The update gets deferred until each of the methods actually gets called.
"""
@@ -1554,28 +1525,23 @@
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
+
Check if one of the marriage years of an individual is in a given range.
+Years are integers.
Expand source code
-
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
+
def marriage_range_match(self, individual: IndividualElement,
+ from_year: int, to_year: int) -> bool:
+ """Check if one of the marriage years of an individual is in a given range.
+ Years are integers.
"""
if not isinstance(individual, IndividualElement):
raise NotAnActualIndividualError(
- "Operation only valid for elements with %s tag" % gedcom.tags.GEDCOM_TAG_INDIVIDUAL
+ "Operation only valid for elements with %s tag" % tags.GEDCOM_TAG_INDIVIDUAL
)
years = self.get_marriage_years(individual)
@@ -1586,26 +1552,22 @@
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
+
Checks if one of the marriage years of an individual matches the supplied year.
+Year is an integer.
Expand source code
-
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
+
def marriage_year_match(self, individual: IndividualElement, year: int) -> bool:
+ """Checks if one of the marriage years of an individual matches the supplied year.
+ Year is an integer.
"""
if not isinstance(individual, IndividualElement):
raise NotAnActualIndividualError(
- "Operation only valid for elements with %s tag" % gedcom.tags.GEDCOM_TAG_INDIVIDUAL
+ "Operation only valid for elements with %s tag" % tags.GEDCOM_TAG_INDIVIDUAL
)
years = self.get_marriage_years(individual)
@@ -1613,20 +1575,16 @@
Parses a stream, or an array of lines, as GEDCOM 5.5 formatted data
-:type gedcom_stream: a file stream, or str array of lines with new line at the end
-:type strict: bool
+
Parses a stream, or an array of lines, as GEDCOM formatted data.
Expand source code
-
def parse(self, gedcom_stream, strict=True):
- """Parses a stream, or an array of lines, as GEDCOM 5.5 formatted data
- :type gedcom_stream: a file stream, or str array of lines with new line at the end
- :type strict: bool
+
def parse(self, gedcom_stream: IO, strict: bool = True):
+ """Parses a stream, or an array of lines, as GEDCOM formatted data.
"""
self.invalidate_cache()
self.__root_element = RootElement()
@@ -1635,27 +1593,37 @@
Methods
last_element = self.get_root_element()
for line in gedcom_stream:
- last_element = self.__parse_line(line_number, line.decode('utf-8-sig'), last_element, strict)
+ last_element = self.__parse_line(line_number, line, last_element, strict)
line_number += 1
Opens and parses a file, from the given file path, as GEDCOM 5.5 formatted data
-:type file_path: str
-:type strict: bool
+
Opens and parses a file, from the given file path, as GEDCOM formatted data.
Expand source code
-
def parse_file(self, file_path, strict=True):
- """Opens and parses a file, from the given file path, as GEDCOM 5.5 formatted data
- :type file_path: str
- :type strict: bool
+
def parse_file(self, file_path: str, strict: bool = True):
+ """Opens and parses a file, from the given file path, as GEDCOM formatted data.
"""
- with open(file_path, 'rb') as gedcom_stream:
+ codec = get_encoding(file_path)
+ real_version, reported_version, reported_format = get_version(file_path, codec)
+
+ if reported_version == '5.5.5':
+ errmsg = "This parser does not properly support the GEDCOM " + reported_version + \
+ " standard at this time\nSee: {0}".format(standards.GEDCOM_5_5_5)
+ raise GedcomVersionUnsupportedError(errmsg)
+
+ if reported_format not in ['LINEAGE-LINKED', 'LINEAGE_LINKED',
+ 'LINAGE-LINKED', 'Lineage - Linked']:
+ errmsg = "This parser does not recognize the GEDCOM format " + reported_format + \
+ " at this time\nSee: {0}".format(standards.GEDCOM_5_5_5)
+ raise GedcomFormatUnsupportedError(errmsg)
+
+ with open(file_path, 'r', encoding=codec) as gedcom_stream:
self.parse(gedcom_stream, strict)
@@ -1663,49 +1631,44 @@
Methods
def print_gedcom(self)
-
Write GEDCOM data to stdout
+
Write GEDCOM data to stdout.
Expand source code
def print_gedcom(self):
- """Write GEDCOM data to stdout"""
- from sys import stdout
+ """Write GEDCOM data to stdout."""
self.save_gedcom(stdout)
Formats all elements and optionally all of the sub-elements into a GEDCOM string
-:type recursive: bool
+
Formats all elements and optionally all of the sub-elements into a
+GEDCOM string.
Expand source code
-
def to_gedcom_string(self, recursive=False):
- """Formats all elements and optionally all of the sub-elements into a GEDCOM string
- :type recursive: bool
+
def to_gedcom_string(self, recursive: bool = False) -> str:
+ """Formats all elements and optionally all of the sub-elements into a
+ GEDCOM string.
"""
is_gte_python_3 = version_info[0] >= 3
output = '' if is_gte_python_3 else b''
@@ -1738,9 +1701,6 @@
Module containing a Reader with higher order methods than the
+base Parser for extracting records as structured data.
+
+
+Expand source code
+
+
# -*- coding: utf-8 -*-
+
+# Python GEDCOM Parser
+#
+# Copyright (C) 2020 Christopher Horn (cdhorn at embarqmail dot com)
+# Copyright (C) 2018 Damon Brodie (damon.brodie at gmail.com)
+# Copyright (C) 2018-2019 Nicklas Reincke (contact at reynke.com)
+# Copyright (C) 2016 Andreas Oberritter
+# Copyright (C) 2012 Madeleine Price Ball
+# Copyright (C) 2005 Daniel Zappala (zappala at cs.byu.edu)
+# Copyright (C) 2005 Brigham Young University
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Further information about the license: http://www.gnu.org/licenses/gpl-2.0.html
+
+"""
+Module containing a `gedcom.reader.Reader` with higher order methods than the
+base `gedcom.parser.Parser` for extracting records as structured data.
+"""
+
+from typing import Union
+
+from gedcom.parser import Parser
+from gedcom.element.header import HeaderElement
+from gedcom.element.individual import IndividualElement
+from gedcom.element.family import FamilyElement
+from gedcom.element.note import NoteElement
+from gedcom.element.object import ObjectElement
+from gedcom.element.source import SourceElement
+from gedcom.element.submission import SubmissionElement
+from gedcom.element.submitter import SubmitterElement
+from gedcom.element.repository import RepositoryElement
+
+ELEMENT_TYPES = {
+ 'header': HeaderElement,
+ 'individual': IndividualElement,
+ 'family': FamilyElement,
+ 'note': NoteElement,
+ 'media': ObjectElement,
+ 'source': SourceElement,
+ 'submission': SubmissionElement,
+ 'submitter': SubmitterElement,
+ 'repository': RepositoryElement
+}
+
+RECORD_KEYS = {
+ 'header': None,
+ 'individual': 'key_to_individual',
+ 'family': 'key_to_family',
+ 'media': 'key_to_object',
+ 'note': 'key_to_note',
+ 'source': 'key_to_source',
+ 'submission': 'key_to_submission',
+ 'submitter': 'key_to_submitter',
+ 'repository': 'key_to_repository'
+}
+
+
+class Reader(Parser):
+ """Simple wrapper around the core `gedcom.parser.Parser` with methods for
+ extracting parsed records as structured data.
+ """
+
+ def get_records_by_type(self, record_type: str,
+ return_output_as_list: bool = True) -> Union[list, dict]:
+ """Return either a list or dictionary with all of the requested records for the
+ given `gedcom.records` record type.
+ """
+ record_list = []
+ record_dict = {}
+
+ for element in self.get_root_child_elements():
+ if isinstance(element, ELEMENT_TYPES[record_type]):
+ record = element.get_record()
+ if return_output_as_list:
+ record_list.append(record)
+ else:
+ if RECORD_KEYS[record_type] is not None:
+ record_dict.update({record[RECORD_KEYS[record_type]]: record})
+ else:
+ record_dict.update({'@HEAD@': record})
+
+ if return_output_as_list:
+ return record_list
+
+ return record_dict
+
+ def get_all_records(self, return_entries_as_list: bool = True) -> dict:
+ """Return a dictionary with all of the available records in the GEDCOM broken
+ down by record type."""
+ record_dict = {}
+
+ for key in RECORD_KEYS:
+ if return_entries_as_list:
+ record_dict.update({key: []})
+ else:
+ record_dict.update({key: {}})
+
+ for element in self.get_root_child_elements():
+ for key in ELEMENT_TYPES:
+ if isinstance(element, ELEMENT_TYPES[key]):
+ record = element.get_record()
+ if return_entries_as_list:
+ record_dict[key].append(record)
+ else:
+ if key != 'header':
+ record_dict[key].update({record[RECORD_KEYS[key]]: record})
+ else:
+ record_dict['header'].update({'@HEAD@': record})
+
+ return record_dict
+
+
+
+
+
+
+
+
+
+
Classes
+
+
+class Reader
+
+
+
Simple wrapper around the core Parser with methods for
+extracting parsed records as structured data.
+
+
+Expand source code
+
+
class Reader(Parser):
+ """Simple wrapper around the core `gedcom.parser.Parser` with methods for
+ extracting parsed records as structured data.
+ """
+
+ def get_records_by_type(self, record_type: str,
+ return_output_as_list: bool = True) -> Union[list, dict]:
+ """Return either a list or dictionary with all of the requested records for the
+ given `gedcom.records` record type.
+ """
+ record_list = []
+ record_dict = {}
+
+ for element in self.get_root_child_elements():
+ if isinstance(element, ELEMENT_TYPES[record_type]):
+ record = element.get_record()
+ if return_output_as_list:
+ record_list.append(record)
+ else:
+ if RECORD_KEYS[record_type] is not None:
+ record_dict.update({record[RECORD_KEYS[record_type]]: record})
+ else:
+ record_dict.update({'@HEAD@': record})
+
+ if return_output_as_list:
+ return record_list
+
+ return record_dict
+
+ def get_all_records(self, return_entries_as_list: bool = True) -> dict:
+ """Return a dictionary with all of the available records in the GEDCOM broken
+ down by record type."""
+ record_dict = {}
+
+ for key in RECORD_KEYS:
+ if return_entries_as_list:
+ record_dict.update({key: []})
+ else:
+ record_dict.update({key: {}})
+
+ for element in self.get_root_child_elements():
+ for key in ELEMENT_TYPES:
+ if isinstance(element, ELEMENT_TYPES[key]):
+ record = element.get_record()
+ if return_entries_as_list:
+ record_dict[key].append(record)
+ else:
+ if key != 'header':
+ record_dict[key].update({record[RECORD_KEYS[key]]: record})
+ else:
+ record_dict['header'].update({'@HEAD@': record})
+
+ return record_dict
Return a dictionary with all of the available records in the GEDCOM broken
+down by record type.
+
+
+Expand source code
+
+
def get_all_records(self, return_entries_as_list: bool = True) -> dict:
+ """Return a dictionary with all of the available records in the GEDCOM broken
+ down by record type."""
+ record_dict = {}
+
+ for key in RECORD_KEYS:
+ if return_entries_as_list:
+ record_dict.update({key: []})
+ else:
+ record_dict.update({key: {}})
+
+ for element in self.get_root_child_elements():
+ for key in ELEMENT_TYPES:
+ if isinstance(element, ELEMENT_TYPES[key]):
+ record = element.get_record()
+ if return_entries_as_list:
+ record_dict[key].append(record)
+ else:
+ if key != 'header':
+ record_dict[key].update({record[RECORD_KEYS[key]]: record})
+ else:
+ record_dict['header'].update({'@HEAD@': record})
+
+ return record_dict
Return either a list or dictionary with all of the requested records for the
+given gedcom.records record type.
+
+
+Expand source code
+
+
def get_records_by_type(self, record_type: str,
+ return_output_as_list: bool = True) -> Union[list, dict]:
+ """Return either a list or dictionary with all of the requested records for the
+ given `gedcom.records` record type.
+ """
+ record_list = []
+ record_dict = {}
+
+ for element in self.get_root_child_elements():
+ if isinstance(element, ELEMENT_TYPES[record_type]):
+ record = element.get_record()
+ if return_output_as_list:
+ record_list.append(record)
+ else:
+ if RECORD_KEYS[record_type] is not None:
+ record_dict.update({record[RECORD_KEYS[record_type]]: record})
+ else:
+ record_dict.update({'@HEAD@': record})
+
+ if return_output_as_list:
+ return record_list
+
+ return record_dict
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/gedcom/records.html b/docs/gedcom/records.html
new file mode 100644
index 0000000..b4abd1f
--- /dev/null
+++ b/docs/gedcom/records.html
@@ -0,0 +1,163 @@
+
+
+
+
+
+
+gedcom.records API documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
Module gedcom.records
+
+
+
Module containing the standard GEDCOM record types recognized by the
+GEDCOM Reader.
+
+
+Expand source code
+
+
# -*- coding: utf-8 -*-
+
+# Python GEDCOM Parser
+#
+# Copyright (C) 2020 Christopher Horn (cdhorn at embarqmail dot com)
+# Copyright (C) 2018 Damon Brodie (damon.brodie at gmail.com)
+# Copyright (C) 2018-2019 Nicklas Reincke (contact at reynke.com)
+# Copyright (C) 2016 Andreas Oberritter
+# Copyright (C) 2012 Madeleine Price Ball
+# Copyright (C) 2005 Daniel Zappala (zappala at cs.byu.edu)
+# Copyright (C) 2005 Brigham Young University
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Further information about the license: http://www.gnu.org/licenses/gpl-2.0.html
+
+"""Module containing the standard GEDCOM record types recognized by the
+GEDCOM `gedcom.reader.Reader`."""
+
+
+GEDCOM_RECORD_FAMILY = 'family'
+"""Identifies the `FAM_RECORD` record type."""
+
+GEDCOM_RECORD_HEADER = 'header'
+"""Identifies the `HEADER` record type."""
+
+GEDCOM_RECORD_INDIVIDUAL = 'individual'
+"""Identifies the `INDIVIDUAL_RECORD` record type."""
+
+GEDCOM_RECORD_NOTE = 'note'
+"""Identifies the `NOTE_RECORD` record type."""
+
+GEDCOM_RECORD_SOURCE = 'source'
+"""Identifies the `SOURCE_RECORD` record type."""
+
+GEDCOM_RECORD_REPOSITORY = 'repository'
+"""Identifies the `REPOSITORY_RECORD` record type."""
+
+GEDCOM_RECORD_SUBMISSION = 'submission'
+"""Identifies the `SUBMISSION_RECORD` record type."""
+
+GEDCOM_RECORD_SUBMITTER = 'submitter'
+"""Identifies the `SUBMITTER_RECORD` record type."""
+
+
+
+
+
+
Global variables
+
+
var GEDCOM_RECORD_FAMILY
+
+
Identifies the FAM_RECORD record type.
+
+
var GEDCOM_RECORD_HEADER
+
+
Identifies the HEADER record type.
+
+
var GEDCOM_RECORD_INDIVIDUAL
+
+
Identifies the INDIVIDUAL_RECORD record type.
+
+
var GEDCOM_RECORD_NOTE
+
+
Identifies the NOTE_RECORD record type.
+
+
var GEDCOM_RECORD_REPOSITORY
+
+
Identifies the REPOSITORY_RECORD record type.
+
+
var GEDCOM_RECORD_SOURCE
+
+
Identifies the SOURCE_RECORD record type.
+
+
var GEDCOM_RECORD_SUBMISSION
+
+
Identifies the SUBMISSION_RECORD record type.
+
+
var GEDCOM_RECORD_SUBMITTER
+
+
Identifies the SUBMITTER_RECORD record type.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/gedcom/standards.html b/docs/gedcom/standards.html
new file mode 100644
index 0000000..59fa416
--- /dev/null
+++ b/docs/gedcom/standards.html
@@ -0,0 +1,130 @@
+
+
+
+
+
+
+gedcom.standards API documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
Module gedcom.standards
+
+
+
Module containing links to the documentation for the various GEDCOM standards.
+
+
+Expand source code
+
+
# -*- coding: utf-8 -*-
+
+# Python GEDCOM Parser
+#
+# Copyright (C) 2020 Christopher Horn (cdhorn at embarqmail dot com)
+# Copyright (C) 2018 Damon Brodie (damon.brodie at gmail.com)
+# Copyright (C) 2018-2019 Nicklas Reincke (contact at reynke.com)
+# Copyright (C) 2016 Andreas Oberritter
+# Copyright (C) 2012 Madeleine Price Ball
+# Copyright (C) 2005 Daniel Zappala (zappala at cs.byu.edu)
+# Copyright (C) 2005 Brigham Young University
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Further information about the license: http://www.gnu.org/licenses/gpl-2.0.html
+
+"""Module containing links to the documentation for the various GEDCOM standards."""
+
+GEDCOM_5_5 = "https://edge.fscdn.org/assets/img/documents/" + \
+ "gedcom55-82e1509bd8dbe7477e3b500e4f62c240.pdf"
+"""The official FamilySearch GEDCOM 5.5 Standard."""
+
+GEDCOM_5_5_1 = "https://edge.fscdn.org/assets/img/documents/" + \
+ "ged551-5bac5e57fe88dd37df0e153d9c515335.pdf"
+"""The official FamilySearch GEDCOM 5.5.1 Standard."""
+
+GEDCOM_5_5_1_GEDCOM_L_ADDENDUM = "https://genealogy.net/GEDCOM/" + \
+ "GEDCOM551%20GEDCOM-L%20Addendum-R1.pdf"
+"""The GEDCOM-L working group GEDCOM 5.5.1 Addendum."""
+
+GEDCOM_5_5_5 = "https://www.gedcom.org/specs/GEDCOM555.zip"
+"""The gedcom.org GEDCOM 5.5.5 Specification With Annotations."""
+
+
+
+
+
+
Global variables
+
+
var GEDCOM_5_5
+
+
The official FamilySearch GEDCOM 5.5 Standard.
+
+
var GEDCOM_5_5_1
+
+
The official FamilySearch GEDCOM 5.5.1 Standard.
+
+
var GEDCOM_5_5_1_GEDCOM_L_ADDENDUM
+
+
The GEDCOM-L working group GEDCOM 5.5.1 Addendum.
+
+
var GEDCOM_5_5_5
+
+
The gedcom.org GEDCOM 5.5.5 Specification With Annotations.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/gedcom/subparsers/address_structure.html b/docs/gedcom/subparsers/address_structure.html
new file mode 100644
index 0000000..ac9c495
--- /dev/null
+++ b/docs/gedcom/subparsers/address_structure.html
@@ -0,0 +1,198 @@
+
+
+
+
+
+
+gedcom.subparsers.address_structure API documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
Module gedcom.subparsers.address_structure
+
+
+
Substructure parser for a ADDRESS_STRUCTURE embedded record.
+
This is referenced as part of a larger structure so there is no anchor tag.
+The GEDCOM_TAG_ADDRESS tag is at the same level as some of
+the other parts of this structure.
+
+
+Expand source code
+
+
# -*- coding: utf-8 -*-
+
+# Python GEDCOM Parser
+#
+# Copyright (C) 2020 Christopher Horn (cdhorn at embarqmail dot com)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Further information about the license: http://www.gnu.org/licenses/gpl-2.0.html
+
+"""
+Substructure parser for a `ADDRESS_STRUCTURE` embedded record.
+
+This is referenced as part of a larger structure so there is no anchor tag.
+The `gedcom.tags.GEDCOM_TAG_ADDRESS` tag is at the same level as some of
+the other parts of this structure.
+"""
+
+import gedcom.tags as tags
+from gedcom.element.element import Element
+
+ADDRESS_TAGS = {
+ tags.GEDCOM_PROGRAM_DEFINED_TAG_ADDRESSE: 'addresse',
+ tags.GEDCOM_TAG_ADDRESS1: 'address1',
+ tags.GEDCOM_TAG_ADDRESS2: 'address2',
+ tags.GEDCOM_TAG_ADDRESS3: 'address3',
+ tags.GEDCOM_TAG_CITY: 'city',
+ tags.GEDCOM_TAG_STATE: 'state',
+ tags.GEDCOM_TAG_POSTAL_CODE: 'postal_code',
+ tags.GEDCOM_TAG_COUNTRY: 'country'
+}
+
+CONTACT_TAGS = {
+ tags.GEDCOM_TAG_PHONE: 'phone',
+ tags.GEDCOM_TAG_EMAIL: 'email',
+ tags.GEDCOM_TAG_FAX: 'fax',
+ tags.GEDCOM_TAG_WWW: 'www'
+}
+
+
+def address_structure(element: Element) -> dict:
+ """Parses and extracts a `ADDRESS_STRUCTURE` structure.
+
+ The `element` should be the parent that contains it.
+ """
+ record = {
+ 'address': '',
+ 'addresse': '',
+ 'address1': '',
+ 'address2': '',
+ 'address3': '',
+ 'city': '',
+ 'state': '',
+ 'postal_code': '',
+ 'country': '',
+ 'phone': [],
+ 'email': [],
+ 'fax': [],
+ 'www': []
+ }
+ for child in element.get_child_elements():
+ if child.get_tag() == tags.GEDCOM_TAG_ADDRESS:
+ record['address'] = child.get_multi_line_value()
+ for gchild in child.get_child_elements():
+ if gchild.get_tag() in ADDRESS_TAGS:
+ record[ADDRESS_TAGS[gchild.get_tag()]] = gchild.get_value()
+ continue
+
+ if child.get_tag() in CONTACT_TAGS:
+ record[CONTACT_TAGS[child.get_tag()]].append(child.get_value())
+
+ return record
# -*- coding: utf-8 -*-
+
+# Python GEDCOM Parser
+#
+# Copyright (C) 2020 Christopher Horn (cdhorn at embarqmail dot com)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Further information about the license: http://www.gnu.org/licenses/gpl-2.0.html
+
+"""
+Substructure parser for the `ASSOCIATION_STRUCTURE` record.
+
+This is anchored by the `gedcom.tags.GEDCOM_TAG_ASSOCIATES` tag.
+"""
+
+import gedcom.tags as tags
+from gedcom.element.element import Element
+from gedcom.subparsers.note_structure import note_structure
+from gedcom.subparsers.source_citation import source_citation
+
+
+def association_structure(element: Element) -> dict:
+ """Parses and extracts the `ASSOCIATION_STRUCTURE` structure.
+
+ The `element` should contain the `gedcom.tags.GEDCOM_TAG_ASSOCIATES` tag.
+ """
+ record = {
+ 'key_to_individual': element.get_value(),
+ 'relationship': '',
+ 'citations': [],
+ 'notes': []
+ }
+ for child in element.get_child_elements():
+ if child.get_tag() == tags.GEDCOM_TAG_RELATIONSHIP:
+ record['relationship'] = child.get_value()
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_NOTE:
+ record['notes'].append(note_structure(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_SOURCE:
+ record['citations'].append(source_citation(child))
+
+ return record
# -*- coding: utf-8 -*-
+
+# Python GEDCOM Parser
+#
+# Copyright (C) 2020 Christopher Horn (cdhorn at embarqmail dot com)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Further information about the license: http://www.gnu.org/licenses/gpl-2.0.html
+
+"""
+Substructure parser for a `CHANGE_DATE` record.
+
+This is anchored by the `gedcom.tags.GEDCOM_TAG_CHANGE` tag.
+"""
+
+import gedcom.tags as tags
+from gedcom.element.element import Element
+from gedcom.subparsers.note_structure import note_structure
+
+
+def change_date(element: Element) -> dict:
+ """Parses and extracts a `CHANGE_DATE` structure.
+
+ The `element` should contain the `gedcom.tags.GEDCOM_TAG_CHANGE` tag.
+ """
+ record = {
+ 'date': '',
+ 'time': '',
+ 'notes': []
+ }
+ for child in element.get_child_elements():
+ if child.get_tag() == tags.GEDCOM_TAG_DATE:
+ record['date'] = child.get_value()
+ for gchild in child.get_child_elements():
+ if gchild.get_tag() == tags.GEDCOM_TAG_TIME:
+ record['time'] = gchild.get_value()
+ continue
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_NOTE:
+ record['notes'].append(note_structure(child))
+
+ return record
# -*- coding: utf-8 -*-
+
+# Python GEDCOM Parser
+#
+# Copyright (C) 2020 Christopher Horn (cdhorn at embarqmail dot com)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Further information about the license: http://www.gnu.org/licenses/gpl-2.0.html
+
+"""
+Substructure parser for a `CHILD_TO_FAMILY_LINK` record.
+
+This is anchored by the `gedcom.tags.GEDCOM_TAG_FAMILY_CHILD` tag.
+"""
+
+import gedcom.tags as tags
+from gedcom.element.element import Element
+from gedcom.subparsers.note_structure import note_structure
+
+
+def child_to_family_link(element: Element) -> dict:
+ """Parses and extracts a `CHILD_TO_FAMILY_LINK` structure.
+
+ The `element` should contain the `gedcom.tags.GEDCOM_TAG_FAMILY_CHILD` tag.
+ """
+ record = {
+ 'key_to_family': element.get_value(),
+ 'pedigree': '',
+ 'status': '',
+ 'notes': []
+ }
+ for child in element.get_child_elements():
+ if child.get_tag() == tags.GEDCOM_TAG_PEDIGREE:
+ record['pedigree'] = child.get_value()
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_STATUS:
+ record['status'] = child.get_value()
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_NOTE:
+ record['notes'].append(note_structure(child))
+
+ return record
def child_to_family_link(element: Element) -> dict:
+ """Parses and extracts a `CHILD_TO_FAMILY_LINK` structure.
+
+ The `element` should contain the `gedcom.tags.GEDCOM_TAG_FAMILY_CHILD` tag.
+ """
+ record = {
+ 'key_to_family': element.get_value(),
+ 'pedigree': '',
+ 'status': '',
+ 'notes': []
+ }
+ for child in element.get_child_elements():
+ if child.get_tag() == tags.GEDCOM_TAG_PEDIGREE:
+ record['pedigree'] = child.get_value()
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_STATUS:
+ record['status'] = child.get_value()
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_NOTE:
+ record['notes'].append(note_structure(child))
+
+ return record
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/gedcom/subparsers/event_detail.html b/docs/gedcom/subparsers/event_detail.html
new file mode 100644
index 0000000..6e6e876
--- /dev/null
+++ b/docs/gedcom/subparsers/event_detail.html
@@ -0,0 +1,212 @@
+
+
+
+
+
+
+gedcom.subparsers.event_detail API documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
Module gedcom.subparsers.event_detail
+
+
+
Substructure parser for a EVENT_DETAIL embedded record.
+
This is referenced as part of a larger structure so there is no anchor tag.
+
+
+Expand source code
+
+
# -*- coding: utf-8 -*-
+
+# Python GEDCOM Parser
+#
+# Copyright (C) 2020 Christopher Horn (cdhorn at embarqmail dot com)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Further information about the license: http://www.gnu.org/licenses/gpl-2.0.html
+
+"""
+Substructure parser for a `EVENT_DETAIL` embedded record.
+
+This is referenced as part of a larger structure so there is no anchor tag.
+"""
+
+import gedcom.tags as tags
+from gedcom.element.element import Element
+from gedcom.subparsers.place_structure import place_structure
+from gedcom.subparsers.address_structure import address_structure
+from gedcom.subparsers.note_structure import note_structure
+from gedcom.subparsers.source_citation import source_citation
+from gedcom.subparsers.multimedia_link import multimedia_link
+
+EVENT_TAGS = {
+ tags.GEDCOM_TAG_TYPE: 'type',
+ tags.GEDCOM_TAG_DATE: 'date',
+ tags.GEDCOM_TAG_AGENCY: 'responsible_agency',
+ tags.GEDCOM_TAG_RELIGION: 'religious_affiliation',
+ tags.GEDCOM_TAG_CAUSE: 'cause_of_event',
+ tags.GEDCOM_TAG_RESTRICTION: 'restriction'
+}
+
+
+def event_detail(element: Element) -> dict:
+ """Parses and extracts a `EVENT_DETAIL` structure.
+
+ The `element` should be the parent that contains it.
+ """
+ record = {
+ 'type': '',
+ 'date': '',
+ 'place': {},
+ 'address': {},
+ 'responsible_agency': '',
+ 'religious_affiliation': '',
+ 'cause_of_event': '',
+ 'restriction_notice': '',
+ 'notes': [],
+ 'citations': [],
+ 'media': []
+ }
+ for child in element.get_child_elements():
+ if child.get_tag() in EVENT_TAGS:
+ record[EVENT_TAGS[child.get_tag()]] = child.get_value()
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_PLACE:
+ record['place'] = place_structure(child)
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_ADDRESS:
+ record['address'] = address_structure(element)
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_NOTE:
+ record['notes'].append(note_structure(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_SOURCE:
+ record['citations'].append(source_citation(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_OBJECT:
+ record['media'].append(multimedia_link(child))
+
+ return record
The element should be the parent that contains it.
+
+
+Expand source code
+
+
def event_detail(element: Element) -> dict:
+ """Parses and extracts a `EVENT_DETAIL` structure.
+
+ The `element` should be the parent that contains it.
+ """
+ record = {
+ 'type': '',
+ 'date': '',
+ 'place': {},
+ 'address': {},
+ 'responsible_agency': '',
+ 'religious_affiliation': '',
+ 'cause_of_event': '',
+ 'restriction_notice': '',
+ 'notes': [],
+ 'citations': [],
+ 'media': []
+ }
+ for child in element.get_child_elements():
+ if child.get_tag() in EVENT_TAGS:
+ record[EVENT_TAGS[child.get_tag()]] = child.get_value()
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_PLACE:
+ record['place'] = place_structure(child)
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_ADDRESS:
+ record['address'] = address_structure(element)
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_NOTE:
+ record['notes'].append(note_structure(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_SOURCE:
+ record['citations'].append(source_citation(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_OBJECT:
+ record['media'].append(multimedia_link(child))
+
+ return record
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/gedcom/subparsers/family_event_detail.html b/docs/gedcom/subparsers/family_event_detail.html
new file mode 100644
index 0000000..51972b5
--- /dev/null
+++ b/docs/gedcom/subparsers/family_event_detail.html
@@ -0,0 +1,155 @@
+
+
+
+
+
+
+gedcom.subparsers.family_event_detail API documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
Module gedcom.subparsers.family_event_detail
+
+
+
Substructure parser for a FAMILY_EVENT_DETAIL emdedded record.
+
This is referenced as part of a larger structure so there is no anchor tag.
+
+
+Expand source code
+
+
# -*- coding: utf-8 -*-
+
+# Python GEDCOM Parser
+#
+# Copyright (C) 2020 Christopher Horn (cdhorn at embarqmail dot com)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Further information about the license: http://www.gnu.org/licenses/gpl-2.0.html
+
+"""
+Substructure parser for a `FAMILY_EVENT_DETAIL` emdedded record.
+
+This is referenced as part of a larger structure so there is no anchor tag.
+"""
+
+import gedcom.tags as tags
+from gedcom.element.element import Element
+from gedcom.subparsers.event_detail import event_detail
+
+
+def family_event_detail(element: Element) -> dict:
+ """Parses and extracts a `FAMILY_EVENT_DETAIL` structure.
+
+ The `element` shouldbe the parent that contains it.
+ """
+ record = event_detail(element)
+ record['husband_age'] = ''
+ record['wife_age'] = ''
+ for child in element.get_child_elements():
+ if child.get_tag() == tags.GEDCOM_TAG_HUSBAND:
+ for gchild in child.get_child_elements():
+ if gchild.get_tag() == tags.GEDCOM_TAG_AGE:
+ record['husband_age'] = gchild.get_value()
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_WIFE:
+ for gchild in child.get_child_elements():
+ if gchild.get_tag() == tags.GEDCOM_TAG_AGE:
+ record['wife_age'] = gchild.get_value()
+
+ return record
Parses and extracts a FAMILY_EVENT_DETAIL structure.
+
The element shouldbe the parent that contains it.
+
+
+Expand source code
+
+
def family_event_detail(element: Element) -> dict:
+ """Parses and extracts a `FAMILY_EVENT_DETAIL` structure.
+
+ The `element` shouldbe the parent that contains it.
+ """
+ record = event_detail(element)
+ record['husband_age'] = ''
+ record['wife_age'] = ''
+ for child in element.get_child_elements():
+ if child.get_tag() == tags.GEDCOM_TAG_HUSBAND:
+ for gchild in child.get_child_elements():
+ if gchild.get_tag() == tags.GEDCOM_TAG_AGE:
+ record['husband_age'] = gchild.get_value()
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_WIFE:
+ for gchild in child.get_child_elements():
+ if gchild.get_tag() == tags.GEDCOM_TAG_AGE:
+ record['wife_age'] = gchild.get_value()
+
+ return record
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/gedcom/subparsers/family_event_structure.html b/docs/gedcom/subparsers/family_event_structure.html
new file mode 100644
index 0000000..972cff6
--- /dev/null
+++ b/docs/gedcom/subparsers/family_event_structure.html
@@ -0,0 +1,160 @@
+
+
+
+
+
+
+gedcom.subparsers.family_event_structure API documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
Module gedcom.subparsers.family_event_structure
+
+
+
Substructure parser for a FAMILY_EVENT_STRUCTURE embedded record.
+
This is referenced as part of a larger structure so there is no anchor tag.
+
+
+Expand source code
+
+
# -*- coding: utf-8 -*-
+
+# Python GEDCOM Parser
+#
+# Copyright (C) 2020 Christopher Horn (cdhorn at embarqmail dot com)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Further information about the license: http://www.gnu.org/licenses/gpl-2.0.html
+
+"""
+Substructure parser for a `FAMILY_EVENT_STRUCTURE` embedded record.
+
+This is referenced as part of a larger structure so there is no anchor tag.
+"""
+
+from typing import List
+
+import gedcom.tags as tags
+from gedcom.element.element import Element
+from gedcom.subparsers.family_event_detail import family_event_detail
+
+EVENT_TAGS = {
+ tags.GEDCOM_TAG_ANNULMENT: 'annulment',
+ tags.GEDCOM_TAG_CENSUS: 'census',
+ tags.GEDCOM_TAG_DIVORCE: 'divorce',
+ tags.GEDCOM_TAG_DIVORCE_FILED: 'divorce_filed',
+ tags.GEDCOM_TAG_ENGAGEMENT: 'engagement',
+ tags.GEDCOM_TAG_MARRIAGE: 'marriage',
+ tags.GEDCOM_TAG_MARRIAGE_BANN: 'marriage_bann',
+ tags.GEDCOM_TAG_MARR_CONTRACT: 'marriage_contract',
+ tags.GEDCOM_TAG_MARR_LICENSE: 'marriage_license',
+ tags.GEDCOM_TAG_MARR_SETTLEMENT: 'marriage_settlement',
+ tags.GEDCOM_TAG_RESIDENCE: 'residence',
+ tags.GEDCOM_TAG_EVENT: 'event'
+}
+
+
+def family_event_structure(element: Element) -> List[dict]:
+ """Parses and extracts a `FAMILY_EVENT_STRUCTURE` structure.
+
+ The `element` should be the parent that contains it.
+ """
+ records = []
+ for child in element.get_child_elements():
+ if child.get_tag() in EVENT_TAGS:
+ record = family_event_detail(child)
+ record['description'] = child.get_multi_line_value()
+ record['tag'] = child.get_tag()
+ record['event'] = EVENT_TAGS[child.get_tag()]
+ records.append(record)
+
+ return records
Parses and extracts a FAMILY_EVENT_STRUCTURE structure.
+
The element should be the parent that contains it.
+
+
+Expand source code
+
+
def family_event_structure(element: Element) -> List[dict]:
+ """Parses and extracts a `FAMILY_EVENT_STRUCTURE` structure.
+
+ The `element` should be the parent that contains it.
+ """
+ records = []
+ for child in element.get_child_elements():
+ if child.get_tag() in EVENT_TAGS:
+ record = family_event_detail(child)
+ record['description'] = child.get_multi_line_value()
+ record['tag'] = child.get_tag()
+ record['event'] = EVENT_TAGS[child.get_tag()]
+ records.append(record)
+
+ return records
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/gedcom/subparsers/index.html b/docs/gedcom/subparsers/index.html
new file mode 100644
index 0000000..6add805
--- /dev/null
+++ b/docs/gedcom/subparsers/index.html
@@ -0,0 +1,221 @@
+
+
+
+
+
+
+gedcom.subparsers API documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
Module gedcom.subparsers
+
+
+
Module containing parsers for extracting various substructures from the
+different record types as defined in the GEDCOM standard.
+
+
+Expand source code
+
+
# -*- coding: utf-8 -*-
+
+# Python GEDCOM Parser
+#
+# Copyright (C) 2020 Christopher Horn (cdhorn at embarqmail dot com)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Further information about the license: http://www.gnu.org/licenses/gpl-2.0.html
+
+"""Module containing parsers for extracting various substructures from the
+different record types as defined in the GEDCOM standard."""
+
+__all__ = [
+ "address_structure",
+ "association_structure",
+ "change_date",
+ "child_to_family_link",
+ "event_detail",
+ "family_event_detail",
+ "family_event_structure",
+ "individual_attribute_structure",
+ "individual_event_detail",
+ "individual_event_structure",
+ "lds_individual_ordinance",
+ "lds_spouse_sealing",
+ "multimedia_link",
+ "note_structure",
+ "personal_name_pieces",
+ "personal_name_structure",
+ "place_structure",
+ "source_citation",
+ "source_repository_citation",
+ "spouse_to_family_link",
+ "user_reference_number"
+]
Substructure parser for the INDIVIDUAL_ATTRIBUTE_STRUCTURE embedded record.
+
This is referenced as part of a larger structure so there is no anchor tag.
+
+
+Expand source code
+
+
# -*- coding: utf-8 -*-
+
+# Python GEDCOM Parser
+#
+# Copyright (C) 2020 Christopher Horn (cdhorn at embarqmail dot com)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Further information about the license: http://www.gnu.org/licenses/gpl-2.0.html
+
+"""
+Substructure parser for the `INDIVIDUAL_ATTRIBUTE_STRUCTURE` embedded record.
+
+This is referenced as part of a larger structure so there is no anchor tag.
+"""
+
+from typing import List
+
+import gedcom.tags as tags
+from gedcom.element.element import Element
+from gedcom.subparsers.individual_event_detail import individual_event_detail
+
+ATTRIBUTE_TAGS = {
+ tags.GEDCOM_TAG_CASTE: 'caste',
+ tags.GEDCOM_TAG_PHY_DESCRIPTION: 'physical_description',
+ tags.GEDCOM_TAG_EDUCATION: 'eduction',
+ tags.GEDCOM_TAG_IDENT_NUMBER: 'identity_number',
+ tags.GEDCOM_TAG_NATIONALITY: 'nationality',
+ tags.GEDCOM_TAG_CHILDREN_COUNT: 'number_of_children',
+ tags.GEDCOM_TAG_MARRIAGE_COUNT: 'number_of_marriages',
+ tags.GEDCOM_TAG_OCCUPATION: 'occupation',
+ tags.GEDCOM_TAG_PROPERTY: 'property',
+ tags.GEDCOM_TAG_RELIGION: 'religion',
+ tags.GEDCOM_TAG_RESIDENCE: 'residence',
+ tags.GEDCOM_TAG_SOC_SEC_NUMBER: 'social_security_number',
+ tags.GEDCOM_TAG_TITLE: 'title',
+ tags.GEDCOM_TAG_FACT: 'fact',
+ tags.GEDCOM_PROGRAM_DEFINED_TAG_DCAUSE: 'cause_of_death'
+}
+
+
+def individual_attribute_structure(element: Element) -> List[dict]:
+ """Parses and extracts the `INDIVIDUAL_ATTRIBUTE_STRUCTURE` structures.
+
+ The `element` should be the parent that contains them.
+ """
+ records = []
+ for child in element.get_child_elements():
+ if child.get_tag() in ATTRIBUTE_TAGS:
+ record = individual_event_detail(child)
+ record['description'] = child.get_multi_line_value()
+ record['tag'] = child.get_tag()
+ record['attribute'] = ATTRIBUTE_TAGS[child.get_tag()]
+ records.append(record)
+ continue
+
+ return records
Parses and extracts the INDIVIDUAL_ATTRIBUTE_STRUCTURE structures.
+
The element should be the parent that contains them.
+
+
+Expand source code
+
+
def individual_attribute_structure(element: Element) -> List[dict]:
+ """Parses and extracts the `INDIVIDUAL_ATTRIBUTE_STRUCTURE` structures.
+
+ The `element` should be the parent that contains them.
+ """
+ records = []
+ for child in element.get_child_elements():
+ if child.get_tag() in ATTRIBUTE_TAGS:
+ record = individual_event_detail(child)
+ record['description'] = child.get_multi_line_value()
+ record['tag'] = child.get_tag()
+ record['attribute'] = ATTRIBUTE_TAGS[child.get_tag()]
+ records.append(record)
+ continue
+
+ return records
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/gedcom/subparsers/individual_event_detail.html b/docs/gedcom/subparsers/individual_event_detail.html
new file mode 100644
index 0000000..0706915
--- /dev/null
+++ b/docs/gedcom/subparsers/individual_event_detail.html
@@ -0,0 +1,137 @@
+
+
+
+
+
+
+gedcom.subparsers.individual_event_detail API documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
Module gedcom.subparsers.individual_event_detail
+
+
+
Substructure parser for a INDIVIDUAL_EVENT_DETAIL emdedded record.
+
This is referenced as part of a larger structure so there is no anchor tag.
+
+
+Expand source code
+
+
# -*- coding: utf-8 -*-
+
+# Python GEDCOM Parser
+#
+# Copyright (C) 2020 Christopher Horn (cdhorn at embarqmail dot com)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Further information about the license: http://www.gnu.org/licenses/gpl-2.0.html
+
+"""
+Substructure parser for a `INDIVIDUAL_EVENT_DETAIL` emdedded record.
+
+This is referenced as part of a larger structure so there is no anchor tag.
+"""
+
+import gedcom.tags as tags
+from gedcom.element.element import Element
+from gedcom.subparsers.event_detail import event_detail
+
+
+def individual_event_detail(element: Element) -> dict:
+ """Parses and extracts a `INDIVIDUAL_EVENT_DETAIL` structure.
+
+ The `element` should be the parent that contains it.
+ """
+ record = event_detail(element)
+ record['age'] = ''
+ for child in element.get_child_elements():
+ if child.get_tag() == tags.GEDCOM_TAG_AGE:
+ record['age'] = child.get_value()
+
+ return record
Parses and extracts a INDIVIDUAL_EVENT_DETAIL structure.
+
The element should be the parent that contains it.
+
+
+Expand source code
+
+
def individual_event_detail(element: Element) -> dict:
+ """Parses and extracts a `INDIVIDUAL_EVENT_DETAIL` structure.
+
+ The `element` should be the parent that contains it.
+ """
+ record = event_detail(element)
+ record['age'] = ''
+ for child in element.get_child_elements():
+ if child.get_tag() == tags.GEDCOM_TAG_AGE:
+ record['age'] = child.get_value()
+
+ return record
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/gedcom/subparsers/individual_event_structure.html b/docs/gedcom/subparsers/individual_event_structure.html
new file mode 100644
index 0000000..dd8eef8
--- /dev/null
+++ b/docs/gedcom/subparsers/individual_event_structure.html
@@ -0,0 +1,233 @@
+
+
+
+
+
+
+gedcom.subparsers.individual_event_structure API documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
Substructure parser for a INDIVIDUAL_EVENT_STRUCTURE embedded record.
+
This is referenced as part of a larger structure so there is no anchor tag.
+
+
+Expand source code
+
+
# -*- coding: utf-8 -*-
+
+# Python GEDCOM Parser
+#
+# Copyright (C) 2020 Christopher Horn (cdhorn at embarqmail dot com)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Further information about the license: http://www.gnu.org/licenses/gpl-2.0.html
+
+"""
+Substructure parser for a `INDIVIDUAL_EVENT_STRUCTURE` embedded record.
+
+This is referenced as part of a larger structure so there is no anchor tag.
+"""
+
+from typing import List
+
+import gedcom.tags as tags
+from gedcom.element.element import Element
+from gedcom.subparsers.individual_event_detail import individual_event_detail
+
+EVENT_TAGS = {
+ tags.GEDCOM_TAG_DEATH: 'death',
+ tags.GEDCOM_TAG_BURIAL: 'burial',
+ tags.GEDCOM_TAG_CREMATION: 'cremation',
+ tags.GEDCOM_TAG_BAPTISM: 'baptism',
+ tags.GEDCOM_TAG_BAR_MITZVAH: 'bar_mitzvah',
+ tags.GEDCOM_TAG_BAS_MITZVAH: 'bas_mitzvah',
+ tags.GEDCOM_TAG_BLESSING: 'blessing',
+ tags.GEDCOM_TAG_ADULT_CHRISTENING: 'adult_christening',
+ tags.GEDCOM_TAG_CONFIRMATION: 'confirmation',
+ tags.GEDCOM_TAG_FIRST_COMMUNION: 'first_communion',
+ tags.GEDCOM_TAG_ORDINATION: 'ordination',
+ tags.GEDCOM_TAG_NATURALIZATION: 'naturalization',
+ tags.GEDCOM_TAG_EMIGRATION: 'emmigration',
+ tags.GEDCOM_TAG_IMMIGRATION: 'immigration',
+ tags.GEDCOM_TAG_CENSUS: 'census',
+ tags.GEDCOM_TAG_PROBATE: 'probate',
+ tags.GEDCOM_TAG_WILL: 'will',
+ tags.GEDCOM_TAG_GRADUATION: 'graduation',
+ tags.GEDCOM_TAG_RETIREMENT: 'retirement',
+ tags.GEDCOM_TAG_EVENT: 'event',
+ tags.GEDCOM_PROGRAM_DEFINED_TAG_DEGREE: 'degree',
+ tags.GEDCOM_PROGRAM_DEFINED_TAG_FUNERAL: 'funeral',
+ tags.GEDCOM_PROGRAM_DEFINED_TAG_MEDICAL: 'medical',
+ tags.GEDCOM_PROGRAM_DEFINED_TAG_MILITARY: 'military'
+}
+
+BIRTH_EVENT_TAGS = {
+ tags.GEDCOM_TAG_BIRTH: 'birth',
+ tags.GEDCOM_TAG_CHRISTENING: 'christening'
+}
+
+
+def individual_event_structure(element: Element) -> List[dict]:
+ """Parses and extracts a `INDIVIDUAL_EVENT_STRUCTURE` structure.
+
+ The `element` should be the parent that contains it.
+ """
+ records = []
+ for child in element.get_child_elements():
+ if child.get_tag() in BIRTH_EVENT_TAGS:
+ record = individual_event_detail(child)
+ record['tag'] = child.get_tag()
+ record['event'] = BIRTH_EVENT_TAGS[child.get_tag()]
+ record['description'] = child.get_multi_line_value()
+ record['family'] = ''
+ for gchild in child.get_child_elements():
+ if gchild.get_tag() == tags.GEDCOM_TAG_FAMILY_CHILD:
+ record['family'] = gchild.get_value()
+ records.append(record)
+ continue
+
+ if child.get_tag() in EVENT_TAGS:
+ record = individual_event_detail(child)
+ record['tag'] = child.get_tag()
+ record['event'] = EVENT_TAGS[child.get_tag()]
+ record['description'] = child.get_multi_line_value()
+ records.append(record)
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_ADOPTION:
+ record = individual_event_detail(child)
+ record['tag'] = child.get_tag()
+ record['event'] = 'adoption'
+ record['description'] = child.get_multi_line_value()
+ record['family'] = ''
+ record['parent'] = ''
+ for gchild in child.get_child_elements():
+ if gchild.get_tag() == tags.GEDCOM_TAG_FAMILY_CHILD:
+ record['family'] = gchild.get_value()
+ for ggchild in gchild.get_child_elements():
+ if ggchild.get_tag() == tags.GEDCOM_TAG_ADOPTION:
+ record['parent'] = ggchild.get_value()
+ records.append(record)
+
+ return records
Parses and extracts a INDIVIDUAL_EVENT_STRUCTURE structure.
+
The element should be the parent that contains it.
+
+
+Expand source code
+
+
def individual_event_structure(element: Element) -> List[dict]:
+ """Parses and extracts a `INDIVIDUAL_EVENT_STRUCTURE` structure.
+
+ The `element` should be the parent that contains it.
+ """
+ records = []
+ for child in element.get_child_elements():
+ if child.get_tag() in BIRTH_EVENT_TAGS:
+ record = individual_event_detail(child)
+ record['tag'] = child.get_tag()
+ record['event'] = BIRTH_EVENT_TAGS[child.get_tag()]
+ record['description'] = child.get_multi_line_value()
+ record['family'] = ''
+ for gchild in child.get_child_elements():
+ if gchild.get_tag() == tags.GEDCOM_TAG_FAMILY_CHILD:
+ record['family'] = gchild.get_value()
+ records.append(record)
+ continue
+
+ if child.get_tag() in EVENT_TAGS:
+ record = individual_event_detail(child)
+ record['tag'] = child.get_tag()
+ record['event'] = EVENT_TAGS[child.get_tag()]
+ record['description'] = child.get_multi_line_value()
+ records.append(record)
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_ADOPTION:
+ record = individual_event_detail(child)
+ record['tag'] = child.get_tag()
+ record['event'] = 'adoption'
+ record['description'] = child.get_multi_line_value()
+ record['family'] = ''
+ record['parent'] = ''
+ for gchild in child.get_child_elements():
+ if gchild.get_tag() == tags.GEDCOM_TAG_FAMILY_CHILD:
+ record['family'] = gchild.get_value()
+ for ggchild in gchild.get_child_elements():
+ if ggchild.get_tag() == tags.GEDCOM_TAG_ADOPTION:
+ record['parent'] = ggchild.get_value()
+ records.append(record)
+
+ return records
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/gedcom/subparsers/lds_individual_ordinance.html b/docs/gedcom/subparsers/lds_individual_ordinance.html
new file mode 100644
index 0000000..cdc657d
--- /dev/null
+++ b/docs/gedcom/subparsers/lds_individual_ordinance.html
@@ -0,0 +1,220 @@
+
+
+
+
+
+
+gedcom.subparsers.lds_individual_ordinance API documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
Module gedcom.subparsers.lds_individual_ordinance
+
+
+
Substructure parser for a LDS_INDIVIDUAL_ORDINANCE embedded record.
+
This is referenced as part of a larger structure so there is no anchor tag.
+
+
+Expand source code
+
+
# -*- coding: utf-8 -*-
+
+# Python GEDCOM Parser
+#
+# Copyright (C) 2020 Christopher Horn (cdhorn at embarqmail dot com)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Further information about the license: http://www.gnu.org/licenses/gpl-2.0.html
+
+"""
+Substructure parser for a `LDS_INDIVIDUAL_ORDINANCE` embedded record.
+
+This is referenced as part of a larger structure so there is no anchor tag.
+"""
+
+from typing import List
+
+import gedcom.tags as tags
+from gedcom.element.element import Element
+from gedcom.subparsers.note_structure import note_structure
+from gedcom.subparsers.source_citation import source_citation
+
+ORDINANCE_TAGS = {
+ tags.GEDCOM_TAG_BAPTISM_LDS: 'lds_baptism',
+ tags.GEDCOM_TAG_CONFIRMATION_L: 'lds_confirmation',
+ tags.GEDCOM_TAG_ENDOWMENT: 'lds_endowment',
+ tags.GEDCOM_TAG_SEALING_CHILD: 'lds_sealing_child'
+}
+
+ORDINANCE_ATTRIBUTE_TAGS = {
+ tags.GEDCOM_TAG_DATE: 'date',
+ tags.GEDCOM_TAG_TEMPLE: 'temple',
+ tags.GEDCOM_TAG_PLACE: 'place',
+ tags.GEDCOM_TAG_FAMILY_CHILD: 'key_to_family'
+}
+
+
+def lds_individual_ordinance(element: Element) -> List[dict]:
+ """Parses and extracts a `LDS_INDIVIDUAL_ORDINANCE` structure.
+
+ The `element` should be the parent that contains it.
+ """
+ records = []
+ for child in element.get_child_elements():
+ if child.get_tag() in ORDINANCE_TAGS:
+ record = {
+ 'date': '',
+ 'temple': '',
+ 'place': '',
+ 'status': '',
+ 'status_change': '',
+ 'notes': [],
+ 'citations': [],
+ 'tag': child.get_tag(),
+ 'event': ORDINANCE_TAGS[child.get_tag()]
+ }
+ if child.get_tag() == tags.GEDCOM_TAG_SEALING_CHILD:
+ record.update({'key_to_family': ''})
+ for gchild in child.get_child_elements():
+ if gchild.get_tag() in ORDINANCE_ATTRIBUTE_TAGS:
+ record[ORDINANCE_ATTRIBUTE_TAGS[gchild.get_tag()]] = gchild.get_value()
+ continue
+
+ if gchild.get_tag() == tags.GEDCOM_TAG_STATUS:
+ record['status'] = gchild.get_value()
+ for ggchild in gchild.get_child_elements():
+ if ggchild.get_tag() == tags.GEDCOM_TAG_DATE:
+ record['status_change'] = ggchild.get_value()
+ continue
+
+ if gchild.get_tag() == tags.GEDCOM_TAG_NOTE:
+ record['notes'].append(note_structure(child))
+ continue
+
+ if gchild.get_tag() == tags.GEDCOM_TAG_SOURCE:
+ record['citations'].append(source_citation(child))
+ continue
+
+ records.append(record)
+ continue
+
+ return records
Parses and extracts a LDS_INDIVIDUAL_ORDINANCE structure.
+
The element should be the parent that contains it.
+
+
+Expand source code
+
+
def lds_individual_ordinance(element: Element) -> List[dict]:
+ """Parses and extracts a `LDS_INDIVIDUAL_ORDINANCE` structure.
+
+ The `element` should be the parent that contains it.
+ """
+ records = []
+ for child in element.get_child_elements():
+ if child.get_tag() in ORDINANCE_TAGS:
+ record = {
+ 'date': '',
+ 'temple': '',
+ 'place': '',
+ 'status': '',
+ 'status_change': '',
+ 'notes': [],
+ 'citations': [],
+ 'tag': child.get_tag(),
+ 'event': ORDINANCE_TAGS[child.get_tag()]
+ }
+ if child.get_tag() == tags.GEDCOM_TAG_SEALING_CHILD:
+ record.update({'key_to_family': ''})
+ for gchild in child.get_child_elements():
+ if gchild.get_tag() in ORDINANCE_ATTRIBUTE_TAGS:
+ record[ORDINANCE_ATTRIBUTE_TAGS[gchild.get_tag()]] = gchild.get_value()
+ continue
+
+ if gchild.get_tag() == tags.GEDCOM_TAG_STATUS:
+ record['status'] = gchild.get_value()
+ for ggchild in gchild.get_child_elements():
+ if ggchild.get_tag() == tags.GEDCOM_TAG_DATE:
+ record['status_change'] = ggchild.get_value()
+ continue
+
+ if gchild.get_tag() == tags.GEDCOM_TAG_NOTE:
+ record['notes'].append(note_structure(child))
+ continue
+
+ if gchild.get_tag() == tags.GEDCOM_TAG_SOURCE:
+ record['citations'].append(source_citation(child))
+ continue
+
+ records.append(record)
+ continue
+
+ return records
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/gedcom/subparsers/lds_spouse_sealing.html b/docs/gedcom/subparsers/lds_spouse_sealing.html
new file mode 100644
index 0000000..8d5d0a1
--- /dev/null
+++ b/docs/gedcom/subparsers/lds_spouse_sealing.html
@@ -0,0 +1,209 @@
+
+
+
+
+
+
+gedcom.subparsers.lds_spouse_sealing API documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
Module gedcom.subparsers.lds_spouse_sealing
+
+
+
Substructure parser for a LDS_SPOUSE_SEALING embedded record.
+
This is referenced as part of a larger structure so there is no anchor tag.
+
+
+Expand source code
+
+
# -*- coding: utf-8 -*-
+
+# Python GEDCOM Parser
+#
+# Copyright (C) 2020 Christopher Horn (cdhorn at embarqmail dot com)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Further information about the license: http://www.gnu.org/licenses/gpl-2.0.html
+
+"""
+Substructure parser for a `LDS_SPOUSE_SEALING` embedded record.
+
+This is referenced as part of a larger structure so there is no anchor tag.
+"""
+
+from typing import List
+
+import gedcom.tags as tags
+from gedcom.element.element import Element
+from gedcom.subparsers.note_structure import note_structure
+from gedcom.subparsers.source_citation import source_citation
+
+SEALING_TAGS = {
+ tags.GEDCOM_TAG_DATE: 'date',
+ tags.GEDCOM_TAG_TEMPLE: 'temple',
+ tags.GEDCOM_TAG_PLACE: 'place',
+ tags.GEDCOM_TAG_FAMILY_CHILD: 'key_to_family'
+}
+
+
+def lds_spouse_sealing(element: Element) -> List[dict]:
+ """Parses and extracts a `LDS_SPOUSE_SEALING` structure.
+
+ The `element` should be the parent that contains it.
+ """
+ records = []
+ for child in element.get_child_elements():
+ if child.get_tag() == tags.GEDCOM_TAG_SEALING_SPOUSE:
+ record = {
+ 'date': '',
+ 'temple': '',
+ 'place': '',
+ 'status': '',
+ 'status_change': '',
+ 'notes': [],
+ 'citations': [],
+ 'tag': tags.GEDCOM_TAG_SEALING_SPOUSE,
+ 'event': 'lds_spouse_sealing'
+ }
+ for gchild in child.get_child_elements():
+ if gchild.get_tag() in SEALING_TAGS:
+ record[SEALING_TAGS[gchild.get_tag()]] = gchild.get_value()
+ continue
+
+ if gchild.get_tag() == tags.GEDCOM_TAG_STATUS:
+ record['status'] = gchild.get_value()
+ for ggchild in gchild.get_child_elements():
+ if ggchild.get_tag() == tags.GEDCOM_TAG_DATE:
+ record['status_change'] = ggchild.get_value()
+ continue
+
+ if gchild.get_tag() == tags.GEDCOM_TAG_NOTE:
+ record['notes'].append(note_structure(child))
+ continue
+
+ if gchild.get_tag() == tags.GEDCOM_TAG_SOURCE:
+ record['citations'].append(source_citation(child))
+ continue
+
+ records.append(record)
+ continue
+
+ return records
# -*- coding: utf-8 -*-
+
+# Python GEDCOM Parser
+#
+# Copyright (C) 2020 Christopher Horn (cdhorn at embarqmail dot com)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Further information about the license: http://www.gnu.org/licenses/gpl-2.0.html
+
+"""
+Substructure parser for a `MULTIMEDIA_LINK` record.
+
+This is anchored by the `gedcom.tags.GEDCOM_TAG_OBJECT` tag.
+"""
+
+import gedcom.tags as tags
+from gedcom.element.element import Element
+
+MEDIA_TAGS = {
+ tags.GEDCOM_TAG_FILE: 'file',
+ tags.GEDCOM_TAG_FORMAT: 'format',
+ tags.GEDCOM_TAG_MEDIA: 'type',
+ tags.GEDCOM_TAG_TITLE: 'title',
+ tags.GEDCOM_PROGRAM_DEFINED_TAG_PHOTO: 'preferred',
+ tags.GEDCOM_PROGRAM_DEFINED_TAG_PRIMARY: 'preferred'
+}
+
+
+def multimedia_link(element: Element) -> dict:
+ """Parse and extract a `MULTIMEDIA_LINK` structure.
+
+ The `element` should contain the `gedcom.tags.GEDCOM_TAG_OBJECT` tag.
+ """
+ record = {
+ 'key_to_object': element.get_value(),
+ 'file': '',
+ 'format': '',
+ 'type': '',
+ 'title': '',
+ 'preferred': ''
+ }
+ if record['key_to_object'] not in [None, '']:
+ if '@' in record['key_to_object']:
+ return record
+
+ record['key_to_object'] = ''
+ for child in element.get_child_elements():
+ if child.get_tag() == tags.GEDCOM_TAG_FILE:
+ record['file'] = child.get_value()
+ for gchild in child.get_child_elements():
+ if gchild.get_tag() == tags.GEDCOM_TAG_FORMAT:
+ record['format'] = gchild.get_value()
+ for ggchild in gchild.get_child_elements():
+ if ggchild.get_tag() == tags.GEDCOM_TAG_MEDIA:
+ record['type'] = ggchild.get_value()
+ continue
+ continue
+
+ if child.get_tag() in MEDIA_TAGS:
+ record[MEDIA_TAGS[child.get_tag()]] = child.get_value()
+
+ return record
# -*- coding: utf-8 -*-
+
+# Python GEDCOM Parser
+#
+# Copyright (C) 2020 Christopher Horn (cdhorn at embarqmail dot com)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Further information about the license: http://www.gnu.org/licenses/gpl-2.0.html
+
+"""
+Substructure parser for a `NOTE_STRUCTURE` record.
+
+This is anchored by the `gedcom.tags.GEDCOM_TAG_NOTE` tag.
+"""
+
+from gedcom.element.element import Element
+
+
+def note_structure(element: Element) -> dict:
+ """Parse and extract a `NOTE_STRUCTURE` structure.
+
+ The `element` should contain the `gedcom.tags.GEDCOM_TAG_NOTE` tag.
+ """
+ record = {
+ 'key_to_note': element.get_value(),
+ 'note': ''
+ }
+ if record['key_to_note'] not in [None, '']:
+ if '@' in record['key_to_note']:
+ return record
+ record['key_to_note'] = ''
+ record['note'] = element.get_multi_line_value()
+
+ return record
def note_structure(element: Element) -> dict:
+ """Parse and extract a `NOTE_STRUCTURE` structure.
+
+ The `element` should contain the `gedcom.tags.GEDCOM_TAG_NOTE` tag.
+ """
+ record = {
+ 'key_to_note': element.get_value(),
+ 'note': ''
+ }
+ if record['key_to_note'] not in [None, '']:
+ if '@' in record['key_to_note']:
+ return record
+ record['key_to_note'] = ''
+ record['note'] = element.get_multi_line_value()
+
+ return record
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/gedcom/subparsers/personal_name_pieces.html b/docs/gedcom/subparsers/personal_name_pieces.html
new file mode 100644
index 0000000..69e94a5
--- /dev/null
+++ b/docs/gedcom/subparsers/personal_name_pieces.html
@@ -0,0 +1,184 @@
+
+
+
+
+
+
+gedcom.subparsers.personal_name_pieces API documentation
+
+
+
+
+
+
+
+
+
+
+
+
+
Module gedcom.subparsers.personal_name_pieces
+
+
+
Substructure parser for a PERSONAL_NAME_PIECES embedded record.
+
This is referenced as part of a larger structure so there is no anchor tag.
+
+
+Expand source code
+
+
# -*- coding: utf-8 -*-
+
+# Python GEDCOM Parser
+#
+# Copyright (C) 2020 Christopher Horn (cdhorn at embarqmail dot com)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Further information about the license: http://www.gnu.org/licenses/gpl-2.0.html
+
+"""
+Substructure parser for a `PERSONAL_NAME_PIECES` embedded record.
+
+This is referenced as part of a larger structure so there is no anchor tag.
+"""
+
+import gedcom.tags as tags
+from gedcom.element.element import Element
+from gedcom.subparsers.note_structure import note_structure
+from gedcom.subparsers.source_citation import source_citation
+
+NAME_TAGS = {
+ tags.GEDCOM_TAG_NAME_PREFIX: 'prefix',
+ tags.GEDCOM_TAG_GIVEN_NAME: 'given',
+ tags.GEDCOM_TAG_NICKNAME: 'nick',
+ tags.GEDCOM_TAG_SURN_PREFIX: 'surname_prefix',
+ tags.GEDCOM_TAG_SURNAME: 'surname',
+ tags.GEDCOM_TAG_NAME_SUFFIX: 'suffix',
+ tags.GEDCOM_PROGRAM_DEFINED_TAG_RUFNAME: 'rufname'
+}
+
+
+def personal_name_pieces(element: Element) -> dict:
+ """Parse and extract a `PERSONAL_NAME_PIECES` structure.
+
+ The `element` should be the parent that contains it.
+ """
+ record = {
+ 'prefix': '',
+ 'given': '',
+ 'nick': '',
+ 'surname_prefix': '',
+ 'surname': '',
+ 'suffix': '',
+ 'rufname': '',
+ 'notes': [],
+ 'citations': []
+ }
+ for child in element.get_child_elements():
+ if child.get_tag() in NAME_TAGS:
+ record[NAME_TAGS[child.get_tag()]] = child.get_value()
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_NOTE:
+ record['notes'].append(note_structure(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_SOURCE:
+ record['citations'].append(source_citation(child))
+ continue
+
+ return record
# -*- coding: utf-8 -*-
+
+# Python GEDCOM Parser
+#
+# Copyright (C) 2020 Christopher Horn (cdhorn at embarqmail dot com)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Further information about the license: http://www.gnu.org/licenses/gpl-2.0.html
+
+"""
+Substructure parser for a `PERSONAL_NAME_STRUCTURE` record.
+
+This is anchored by the `gedcom.tags.GEDCOM_TAG_NAME` tag.
+"""
+
+import gedcom.tags as tags
+from gedcom.element.element import Element
+from gedcom.subparsers.personal_name_pieces import personal_name_pieces
+
+
+def extract_name(element: Element) -> dict:
+ """Parse and extract a `NAME` for a `PERSONAL_NAME_STRUCTURE` structure.
+
+ The `element` should contain one of the name tags:
+
+ `gedcom.tags.GEDCOM_TAG_NAME`
+
+ `gedcom.tags.GEDCOM_TAG_PHONETIC`
+
+ `gedcom.tags.GEDCOM_TAG_ROMANIZED`
+ """
+ record = {
+ 'name': '',
+ 'type': '',
+ 'pieces': {}
+ }
+ record['name'] = element.get_value()
+ record['pieces'] = personal_name_pieces(element)
+ for child in element.get_child_elements():
+ if child.get_tag() == tags.GEDCOM_TAG_TYPE:
+ record['type'] = child.get_value()
+ return record
+
+
+def personal_name_structure(element: Element) -> dict:
+ """Parse and extract a `PERSONAL_NAME_STRUCTURE` structure.
+
+ The `element` should contain the `gedcom.tags.GEDCOM_TAG_NAME` tag.
+ """
+ record = extract_name(element)
+ record['phonetic'] = []
+ record['romanized'] = []
+ for child in element.get_child_elements():
+ if child.get_tag() == tags.GEDCOM_TAG_PHONETIC:
+ record['phonetic'].append(extract_name(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_ROMANIZED:
+ record['romanized'].append(extract_name(child))
+ continue
+
+ return record
# -*- coding: utf-8 -*-
+
+# Python GEDCOM Parser
+#
+# Copyright (C) 2020 Christopher Horn (cdhorn at embarqmail dot com)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Further information about the license: http://www.gnu.org/licenses/gpl-2.0.html
+
+"""
+Substructure parser for a `PLACE_STRUCTURE` record.
+
+This is anchored by the `gedcom.tags.GEDCOM_TAG_PLACE` tag.
+"""
+
+import gedcom.tags as tags
+from gedcom.element.element import Element
+from gedcom.subparsers.note_structure import note_structure
+
+
+def place_structure(element: Element) -> dict:
+ """Parse and extract a `PLACE_STRUCTURE` structure.
+
+ The `element` should contain the `gedcom.tags.GEDCOM_TAG_PLACE` tag.
+ """
+ record = {
+ 'name': element.get_value(),
+ 'hierarchy': '',
+ 'phonetic': [],
+ 'romanized': [],
+ 'latitude': '',
+ 'longitude': '',
+ 'notes': []
+ }
+ for child in element.get_child_elements():
+ if child.get_tag() == tags.GEDCOM_TAG_FORMAT:
+ record['hierarchy'] = child.get_value()
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_NOTE:
+ record['notes'].append(note_structure(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_PHONETIC:
+ subrecord = {
+ 'name': child.get_value(),
+ 'type': ''
+ }
+ for gchild in child.get_child_elements():
+ if gchild.get_tag() == tags.GEDCOM_TAG_TYPE:
+ subrecord['type'] = gchild.get_value()
+ record['phonetic'].append(subrecord)
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_ROMANIZED:
+ subrecord = {
+ 'name': child.get_value(),
+ 'type': ''
+ }
+ for gchild in child.get_child_elements():
+ if gchild.get_tag() == tags.GEDCOM_TAG_TYPE:
+ subrecord['type'] = gchild.get_value()
+ record['romanized'].append(subrecord)
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_MAP:
+ for gchild in child.get_child_elements():
+ if gchild.get_tag() == tags.GEDCOM_TAG_LATITUDE:
+ record['latitude'] = gchild.get_value()
+ continue
+
+ if gchild.get_tag() == tags.GEDCOM_TAG_LONGITUDE:
+ record['longitude'] = gchild.get_value()
+
+ return record
# -*- coding: utf-8 -*-
+
+# Python GEDCOM Parser
+#
+# Copyright (C) 2020 Christopher Horn (cdhorn at embarqmail dot com)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Further information about the license: http://www.gnu.org/licenses/gpl-2.0.html
+
+"""
+Substructure parser for a `SOURCE_CITATION` record.
+
+This is anchored by the `gedcom.tags.GEDCOM_TAG_SOURCE` tag.
+"""
+
+import gedcom.tags as tags
+from gedcom.element.element import Element
+from gedcom.subparsers.multimedia_link import multimedia_link
+from gedcom.subparsers.note_structure import note_structure
+
+CITATION_TAGS = {
+ tags.GEDCOM_TAG_PAGE: 'page',
+ tags.GEDCOM_TAG_DATE: 'date',
+ tags.GEDCOM_TAG_QUALITY_OF_DATA: 'quality',
+ tags.GEDCOM_PROGRAM_DEFINED_TAG_APID: 'apid'
+}
+
+
+def source_citation(element: Element) -> dict:
+ """Parse and extract a `SOURCE_CITATION` structure.
+
+ The `element` should contain the `gedcom.tags.GEDCOM_TAG_SOURCE` tag.
+ """
+ record = {
+ 'key_to_source': element.get_value(),
+ 'source': '',
+ 'page': '',
+ 'event': '',
+ 'role': '',
+ 'date': '',
+ 'text': '',
+ 'media': [],
+ 'notes': [],
+ 'quality': '',
+ 'apid': ''
+ }
+ if record['key_to_source'] not in [None, '']:
+ if '@' not in record['key_to_source']:
+ record['key_to_source'] = ''
+ record['source'] = element.get_multi_line_value()
+
+ for child in element.get_child_elements():
+ if child.get_tag() in CITATION_TAGS:
+ record[CITATION_TAGS[child.get_tag()]] = child.get_value()
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_EVENT:
+ record['event'] = child.get_value()
+ for gchild in child.get_child_elements():
+ if gchild.get_tag() == tags.GEDCOM_TAG_ROLE:
+ record['role'] = gchild.get_value()
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_DATA:
+ for gchild in child.get_child_elements():
+ if gchild.get_tag() == tags.GEDCOM_TAG_DATE:
+ record['date'] = gchild.get_value()
+ continue
+ if gchild.get_tag() == tags.GEDCOM_TAG_TEXT:
+ record['text'] = gchild.get_multi_line_value()
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_OBJECT:
+ record['media'].append(multimedia_link(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_NOTE:
+ record['notes'].append(note_structure(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_TEXT:
+ record['text'] = child.get_multi_line_value()
+
+ return record
# -*- coding: utf-8 -*-
+
+# Python GEDCOM Parser
+#
+# Copyright (C) 2020 Christopher Horn (cdhorn at embarqmail dot com)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Further information about the license: http://www.gnu.org/licenses/gpl-2.0.html
+
+"""
+Substructure parser for a `SOURCE_REPOSITORY_CITATION` record.
+
+This is anchored by the `gedcom.tags.GEDCOM_TAG_REPOSITORY` tag.
+"""
+
+import gedcom.tags as tags
+from gedcom.element.element import Element
+from gedcom.subparsers.note_structure import note_structure
+
+
+def source_repository_citation(element: Element) -> dict:
+ """Parse and extract a `SOURCE_REPOSITORY_CITATION` structure.
+
+ The `element` should contain the `gedcom.tags.GEDCOM_TAG_REPOSITORY` tag.
+ """
+ record = {
+ 'key_to_repository': element.get_value(),
+ 'call_number': '',
+ 'media_type': '',
+ 'notes': []
+ }
+ if record['key_to_repository'] not in [None, '']:
+ if '@' not in record['key_to_repository']:
+ record['key_to_repository'] = ''
+
+ for child in element.get_child_elements():
+ if child.get_tag() == tags.GEDCOM_TAG_NOTE:
+ record['notes'].append(note_structure(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_CALL_NUMBER:
+ record['call_number'] = child.get_value()
+ for gchild in child.get_child_elements():
+ if gchild.get_tag() == tags.GEDCOM_TAG_MEDIA:
+ record['media_type'] = gchild.get_value()
+
+ return record
# -*- coding: utf-8 -*-
+
+# Python GEDCOM Parser
+#
+# Copyright (C) 2020 Christopher Horn (cdhorn at embarqmail dot com)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Further information about the license: http://www.gnu.org/licenses/gpl-2.0.html
+
+"""
+Substructure parser for a `SPOUSE_TO_FAMILY_LINK` record.
+
+This is anchored by the `gedcom.tags.GEDCOM_TAG_FAMILY_SPOUSE` tag.
+"""
+
+import gedcom.tags as tags
+from gedcom.element.element import Element
+from gedcom.subparsers.note_structure import note_structure
+
+
+def spouse_to_family_link(element: Element) -> dict:
+ """Parse and extract a `SPOUSE_TO_FAMILY_LINK` structure.
+
+ The `element` should contain the `gedcom.tags.GEDCOM_TAG_FAMILY_SPOUSE` tag.
+ """
+ record = {
+ 'key_to_family': element.get_value(),
+ 'notes': []
+ }
+ for child in element.get_child_elements():
+ if child.get_tag() == tags.GEDCOM_TAG_NOTE:
+ record['notes'].append(note_structure(child))
+
+ return record
This is not a formally documented structure in the standard but it is
+a substructure that repeats itself in a number of record types.
+
+
+Expand source code
+
+
# -*- coding: utf-8 -*-
+
+# Python GEDCOM Parser
+#
+# Copyright (C) 2020 Christopher Horn (cdhorn at embarqmail dot com)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Further information about the license: http://www.gnu.org/licenses/gpl-2.0.html
+
+"""
+Parser for a `USER_REFERENCE_NUMBER` structure.
+
+This is anchored by the `gedcom.tags.GEDCOM_TAG_REFERENCE` tag.
+
+This is not a formally documented structure in the standard but it is
+a substructure that repeats itself in a number of record types.
+"""
+
+import gedcom.tags as tags
+from gedcom.element.element import Element
+
+
+def user_reference_number(element: Element) -> dict:
+ """Parse and extract a `USER_REFERENCE_NUMBER` structure.
+
+ The `element` should contain the `gedcom.tags.GEDCOM_TAG_REFERENCE` tag.
+ """
+ record = {
+ 'reference': element.get_value(),
+ 'type': ''
+ }
+ for child in element.get_child_elements():
+ if child.get_tag() == tags.GEDCOM_TAG_TYPE:
+ record['type'] = child.get_value()
+
+ return record
def user_reference_number(element: Element) -> dict:
+ """Parse and extract a `USER_REFERENCE_NUMBER` structure.
+
+ The `element` should contain the `gedcom.tags.GEDCOM_TAG_REFERENCE` tag.
+ """
+ record = {
+ 'reference': element.get_value(),
+ 'type': ''
+ }
+ for child in element.get_child_elements():
+ if child.get_tag() == tags.GEDCOM_TAG_TYPE:
+ record['type'] = child.get_value()
+
+ return record
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/docs/gedcom/tags.html b/docs/gedcom/tags.html
index f1c5491..ae9d7c5 100644
--- a/docs/gedcom/tags.html
+++ b/docs/gedcom/tags.html
@@ -3,14 +3,14 @@
-
+
gedcom.tags API documentation
-
+
-
-
+
+
@@ -20,7 +20,7 @@
Module gedcom.tags
-
GEDCOM tags.
+
Module containing the standard GEDCOM tags and some of the most common program defined extensions.
Expand source code
@@ -29,6 +29,7 @@
Module gedcom.tags
# Python GEDCOM Parser
#
+# Copyright (C) 2020 Christopher Horn (cdhorn at embarqmail dot com)
# Copyright (C) 2018 Damon Brodie (damon.brodie at gmail.com)
# Copyright (C) 2018-2019 Nicklas Reincke (contact at reynke.com)
# Copyright (C) 2016 Andreas Oberritter
@@ -53,63 +54,392 @@
Module gedcom.tags
# Further information about the license: http://www.gnu.org/licenses/gpl-2.0.html
"""
-GEDCOM tags.
+Module containing the standard GEDCOM tags and some of the most common program defined extensions.
"""
-GEDCOM_PROGRAM_DEFINED_TAG_MREL = "_MREL"
-"""Value: `_MREL`
+GEDCOM_PROGRAM_DEFINED_TAG_ADDRESSE = "_NAME"
+"""Value: `_NAME`
+
+Name of addresse in a `gedcom.tags.GEDCOM_TAG_ADDRESS` structure.
+
+5.5.1 GEDCOM-L Addendum."""
+
+GEDCOM_PROGRAM_DEFINED_TAG_ADMINISTRATIVE_ID = "_AIDN"
+"""Value: `_AIDN`
+
+Identifier for a location with the intention of an administrative authority,
+e.g. community identifier.
+
+5.5.1 GEDCOM-L Addendum."""
+
+GEDCOM_PROGRAM_DEFINED_TAG_APID = "_APID"
+"""Value: `_APID`
+
+Ancestry page identifier. For a citation, points to the page in a Ancestry
+database for the record supporting the citation. For a source record it
+points to the database as a whole.
+
+Ancestry.com Extension."""
+
+GEDCOM_PROGRAM_DEFINED_TAG_DCAUSE = "_DCAUSE"
+"""Value: `_DCAUSE`
+
+Cause of death."""
+
+GEDCOM_PROGRAM_DEFINED_TAG_DEGREE = "_DEG"
+"""Value: `_DEG`
+
+Degree or recognition of accomplishment received by an individual."""
+
+GEDCOM_PROGRAM_DEFINED_TAG_DEMOGRAPHIC_DATA = "_DMGD"
+"""Value: `_DMGD`
+
+A number of ojects, during an ascertainment, e.g. the count of households.
-Relationship to a mother."""
+5.5.1 GEDCOM-L Addendum."""
GEDCOM_PROGRAM_DEFINED_TAG_FREL = "_FREL"
"""Value: `_FREL`
-Relationship to a father."""
+Type of relationship between child and the father in a family."""
+
+GEDCOM_PROGRAM_DEFINED_TAG_FUNERAL = "_FUN"
+"""Value: `_FUN`
+
+Funeral for an individual."""
+
+GEDCOM_PROGRAM_DEFINED_TAG_GOVERNMENT = "_GOV"
+"""Value: `_GOV`
+
+The official government id of the object in the Historical Place Register /
+Historic Gazeteer.
+
+5.5.1 GEDCOM-L Addendum."""
+
+GEDCOM_PROGRAM_DEFINED_TAG_GOVERNMENT_TYPE = "_GOVTYPE"
+"""Value: `_GOVTYPE`
+
+An integer positive number as defined in the GOV system.
+See http://gov.genealogy.net.net/type/list.
+
+5.5.1 GEDCOM-L Addendum."""
+
+GEDCOM_PROGRAM_DEFINED_TAG_HOME_PERSON = "_HME"
+"""Value: `_HME`
+
+Home person in the tree."""
+
+GEDCOM_PROGRAM_DEFINED_TAG_LOCATION = "_LOC"
+"""Value: `_LOC`
+
+Location data record.
+
+5.5.1 GEDCOM-L Addendum."""
+
+GEDCOM_PROGRAM_DEFINED_TAG_MAIDENHEAD = "_MAIDENHEAD"
+"""Value: `_MAIDENHEAD`
+
+The maidenhead code.
+
+5.5.1 GEDCOM-L Addendum."""
+
+GEDCOM_PROGRAM_DEFINED_TAG_MEDICAL = "_MDCL"
+"""Value: `_MDCL`
+
+Medical information about an individual."""
+
+GEDCOM_PROGRAM_DEFINED_TAG_MILITARY = "_MILT"
+"""Value: `_MILT`
+
+A military related event in the individuals life."""
+
+GEDCOM_PROGRAM_DEFINED_TAG_MREL = "_MREL"
+"""Value: `_MREL`
+
+Type of relationship between child and the mother in a family."""
+
+GEDCOM_PROGRAM_DEFINED_TAG_PHOTO = "_PHOTO"
+"""Value: `_PHOTO`
+
+Used by some programs to identify the primary multimedia object for an
+individual, the same as `gedcom.tags.GEDCOM_PROGRAM_DEFINED_TAG_PRIMARY`."""
+
+GEDCOM_PROGRAM_DEFINED_TAG_POSTAL_CODE = "_POST"
+"""Value: `_POST`
+
+The official zip code, called ADDRESS_POSTAL_CODE in the standard.
+
+5.5.1 GEDCOM-L Addendum."""
+
+GEDCOM_PROGRAM_DEFINED_TAG_PREFERRED = "_PREF"
+"""Value: `_PREF`
+
+Indicates a preferred spouse, child or parents."""
+
+GEDCOM_PROGRAM_DEFINED_TAG_PRIMARY = "_PRIM"
+"""Value: `_PRIM`
+
+Primary multimedia object for an individual."""
+
+GEDCOM_PROGRAM_DEFINED_TAG_SCHEMA = "_SCHEMA"
+"""Value: `_SCHEMA`
+
+Schema substructure extension to describe user defined tags.
+
+5.5.1 GEDCOM-L Addendum."""
+
+GEDCOM_PROGRAM_DEFINED_TAG_RUFNAME = "_RUFNAME"
+"""Value: `_RUFNAME`
+
+An official given name of a German individual used in legal documents.
+
+5.5.1 GEDCOM-L Addendum."""
+
+GEDCOM_PROGRAM_DEFINED_TAG_UUID = "_UID"
+"""Value: `_UID`
+
+Universal identification number.
+
+5.5.1 GEDCOM-L Addendum."""
+
+GEDCOM_TAG_ABBREVIATION = "ABBR"
+"""Value: `ABBR`
+
+A short name of a title, description, or name."""
+
+GEDCOM_TAG_ADDRESS = "ADDR"
+"""Value: `ADDR`
+
+The contemporary place, usually required for postal purposes, of an individual,
+a submitter of information, a repository, a business, a school, or a company."""
+
+GEDCOM_TAG_ADDRESS1 = "ADR1"
+"""Value: `ADR1`
+
+The first line of an address."""
+
+GEDCOM_TAG_ADDRESS2 = "ADR2"
+"""Value: `ADR2`
+
+The second line of an address."""
+
+GEDCOM_TAG_ADDRESS3 = "ADR3"
+"""Value: `ADR3`
+
+The third line of an address."""
+
+GEDCOM_TAG_ADOPTION = "ADOP"
+"""Value: `ADOP`
+
+Pertaining to creation of a child-parent relationship that does not exist
+biologically."""
+
+GEDCOM_TAG_AFN = "AFN"
+"""Value: `AFN`
+
+Ancestral File Number, a unique permanent record file number of an individual
+record stored in Ancestral File."""
+
+GEDCOM_TAG_AGE = "AGE"
+"""Value: `AGE`
+
+The age of the individual at the time an event occurred, or the age listed in
+the document."""
+
+GEDCOM_TAG_AGENCY = "AGNC"
+"""Value: `AGNC`
+
+The institution or individual having authority and/or responsibility to manage
+or govern."""
+
+GEDCOM_TAG_ALIAS = "ALIA"
+"""Value: `ALIA`
+
+An indicator to link different record descriptions of a person who may be the
+same person."""
+
+GEDCOM_TAG_ANCESTORS = "ANCE"
+"""Value: `ANCE`
+
+Pertaining to forbearers of an individual."""
+
+GEDCOM_TAG_ANCES_INTEREST = "ANCI"
+"""Value: `ANCI`
+
+Indicates an interest in additional research for ancestors of this individual.
+(See also `gedcom.tags.GEDCOM_TAG_DESCENDANTS_INT`)"""
+
+GEDCOM_TAG_ANNULMENT = "ANUL"
+"""Value: `ANUL`
+
+Declaring a marriage void from the beginning (never existed)."""
+
+GEDCOM_TAG_ASSOCIATES = "ASSO"
+"""Value: `ASSO`
+
+An indicator to link friends, neighbors, relatives, or associates of an
+individual."""
+
+GEDCOM_TAG_AUTHOR = "AUTH"
+"""Value: `AUTH`
+
+The name of the individual who created or compiled information."""
+
+GEDCOM_TAG_BAPTISM_LDS = "BAPL"
+"""Value: `BAPL`
+
+The event of baptism performed at age eight or later by priesthood authority
+of the LDS Church. (See also `gedcom.tags.GEDCOM_TAG_BAPTISM`)"""
+
+GEDCOM_TAG_BAPTISM = "BAPM"
+"""Value: `BAPM`
+
+The event of baptism (not LDS), performed in infancy or later."""
+
+GEDCOM_TAG_BAR_MITZVAH = "BARM"
+"""Value: `BARM`
+
+The ceremonial event held when a Jewish boy reaches age 13."""
+
+GEDCOM_TAG_BAS_MITZVAH = "BASM"
+"""Value: `BASM`
+
+The ceremonial event held when a Jewish girl reaches age 13, also known as
+Bat Mitzvah."""
GEDCOM_TAG_BIRTH = "BIRT"
"""Value: `BIRT`
The event of entering into life."""
+GEDCOM_TAG_BLESSING = "BLES"
+"""Value: `BLES`
+
+A religious event of bestowing divine care or intercession. Sometimes given
+in connection with a naming ceremony."""
+
GEDCOM_TAG_BURIAL = "BURI"
"""Value: `BURI`
The event of the proper disposing of the mortal remains of a deceased person."""
+GEDCOM_TAG_CALL_NUMBER = "CALN"
+"""Value: `CALN`
+
+The number used by a repository to identify the specific items in its
+collections."""
+
+GEDCOM_TAG_CASTE = "CAST"
+"""Value: `CAST`
+
+The name of an individual's rank or status in society, based on racial or
+religious differences, or differences in wealth, inherited rank, profession,
+occupation, etc."""
+
+GEDCOM_TAG_CAUSE = "CAUSE"
+"""Value: `CAUS`
+
+A description of the cause of the associated event or fact, such as the cause
+of death."""
+
GEDCOM_TAG_CENSUS = "CENS"
"""Value: `CENS`.
-The event of the periodic count of the population for a designated locality, such as a national or state Census."""
+The event of the periodic count of the population for a designated locality,
+such as a national or state Census."""
GEDCOM_TAG_CHANGE = "CHAN"
"""Value: `CHAN`
Indicates a change, correction, or modification. Typically used in connection
-with a `gedcom.tags.GEDCOM_TAG_DATE` to specify when a change in information occurred."""
+with a `gedcom.tags.GEDCOM_TAG_DATE` to specify when a change in information
+occurred."""
+
+GEDCOM_TAG_CHARACTER = "CHAR"
+"""Value: `CHAR`
+
+An indicator of the character set used in writing this automated information."""
GEDCOM_TAG_CHILD = "CHIL"
"""Value: `CHIL`
The natural, adopted, or sealed (LDS) child of a father and a mother."""
+GEDCOM_TAG_CHRISTENING = "CHR"
+"""Value: `CHR`
+
+The religious event (not LDS) of baptizing and/or naming a child."""
+
+GEDCOM_TAG_ADULT_CHRISTENING = "CHRA"
+"""Value: `CHRA`
+
+The religious event (not LDS) of baptizing and/or naming an adult person."""
+
+GEDCOM_TAG_CITY = "CITY"
+"""Value: `CITY`
+
+A lower level jurisdictional unit. Normally an incorporated municipal unit."""
+
GEDCOM_TAG_CONCATENATION = "CONC"
"""Value: `CONC`
-An indicator that additional data belongs to the superior value. The information from the `CONC` value is to
-be connected to the value of the superior preceding line without a space and without a carriage return and/or
-new line character. Values that are split for a `CONC` tag must always be split at a non-space. If the value is
-split on a space the space will be lost when concatenation takes place. This is because of the treatment that
-spaces get as a GEDCOM delimiter, many GEDCOM values are trimmed of trailing spaces and some systems look for
-the first non-space starting after the tag to determine the beginning of the value."""
+An indicator that additional data belongs to the superior value. The information
+from the `CONC` value is to be connected to the value of the superior preceding
+line without a space and without a carriage return and/or new line character.
+Values that are split for a `CONC` tag must always be split at a non-space. If
+the value is split on a space the space will be lost when concatenation takes
+place. This is because of the treatment that spaces get as a GEDCOM delimiter,
+many GEDCOM values are trimmed of trailing spaces and some systems look for
+the first non-space starting after the tag to determine the beginning of the
+value."""
+
+GEDCOM_TAG_CONFIRMATION = "CONF"
+"""Value: `CONF`
+
+The religious event (not LDS) of conferring the gift of the Holy Ghost and,
+among protestants, full church membership."""
+
+GEDCOM_TAG_CONFIRMATION_L = "CONL"
+"""Value: `CONL`
+
+The religious event by which a person receives membership in the LDS Church."""
GEDCOM_TAG_CONTINUED = "CONT"
"""Value: `CONT`
-An indicator that additional data belongs to the superior value. The information from the `CONT` value is to be
-connected to the value of the superior preceding line with a carriage return and/or new line character.
-Leading spaces could be important to the formatting of the resultant text. When importing values from `CONT` lines
-the reader should assume only one delimiter character following the `CONT` tag. Assume that the rest of the leading
-spaces are to be a part of the value."""
+An indicator that additional data belongs to the superior value. The information
+from the `CONT` value is to be connected to the value of the superior preceding
+line with a carriage return and/or new line character. Leading spaces could be
+important to the formatting of the resultant text. When importing values from
+`CONT` lines the reader should assume only one delimiter character following
+the `CONT` tag. Assume that the rest of the leading spaces are to be a part
+of the value."""
+
+GEDCOM_TAG_COPYRIGHT = "COPR"
+"""Value: `COPR`
+
+A statement that accompanies data to protect it from unlawful duplication
+and distribution."""
+
+GEDCOM_TAG_CORPORATE = "CORP"
+"""Value: `CORP`
+
+A name of an institution, agency, corporation, or company."""
+
+GEDCOM_TAG_CREMATION = "CREM"
+"""Value: `CREM`
+
+Disposal of the remains of a person's body by fire."""
+
+GEDCOM_TAG_COUNTRY = "CTRY"
+"""Value: `CTRY`
+
+The name or code of a country."""
+
+GEDCOM_TAG_DATA = "DATA"
+"""Value: `DATA`
+
+Pertaining to stored automation information."""
GEDCOM_TAG_DATE = "DATE"
"""Value: `DATE`
@@ -121,93 +451,542 @@
Module gedcom.tags
The event when mortal life terminates."""
+GEDCOM_TAG_DESCENDANTS = "DESC"
+"""Value: `DESC`
+
+Pertaining to offspring of an individual."""
+
+GEDCOM_TAG_DESCENDANTS_INT = "DESI"
+"""Value: `DESI`
+
+Indicates an interest in research to identify additional descendants of this
+individual. (See also `gedcom.tags.GEDCOM_TAG_ANCES_INTEREST`)"""
+
+GEDCOM_TAG_DESTINATION = "DEST"
+"""Value: `DEST`
+
+A system receiving data."""
+
+GEDCOM_TAG_DIVORCE = "DIV"
+"""Value: `DIV`
+
+The event of disolving a marriage through civil action."""
+
+GEDCOM_TAG_DIVORCE_FILED = "DIVF"
+"""Value: `DIVF`
+
+An event of filing for a divorce by a spouse."""
+
+GEDCOM_TAG_PHY_DESCRIPTION = "DSCR"
+"""Value: `DSCR`
+
+The physical characteristics of a person, place, or thing."""
+
+GEDCOM_TAG_EDUCATION = "EDUC"
+"""Value: `EDUC`
+
+Indicator of a level of education attained."""
+
+GEDCOM_TAG_EMAIL = "EMAIL"
+"""Value: `EMAIL`
+
+An electronic address that can be used for contact such as an email address."""
+
+GEDCOM_TAG_EMIGRATION = "EMIG"
+"""Value: `EMIG`
+
+An event of leaving one's homeland with the intent of residing elsewhere."""
+
+GEDCOM_TAG_ENDOWMENT = "ENDL"
+"""Value: `ENDL`
+
+A religious event where an endowment ordinance for an individual was performed
+by priesthood authority in an LDS temple."""
+
+GEDCOM_TAG_ENGAGEMENT = "ENGA"
+"""Value: `ENGA`
+
+An event of recording or announcing an agreement between two people to become
+married."""
+
+GEDCOM_TAG_EVENT = "EVEN"
+"""Value: `EVEN`
+
+A noteworthy happening related to an individual, a group, or an organization."""
+
+GEDCOM_TAG_FACT = "FACT"
+"""Value: `FACT`
+
+Pertaining to a noteworthy attribute or fact concerning an individual, a group,
+or an organization. A `FACT` structure is usually qualified or classified by a
+subordinate use of the `gedcom.tags.GEDCOM_TAG_TYPE` tag."""
+
GEDCOM_TAG_FAMILY = "FAM"
"""Value: `FAM`.
-Identifies a legal, common law, or other customary relationship of man and woman and their children,
-if any, or a family created by virtue of the birth of a child to its biological father and mother."""
+Identifies a legal, common law, or other customary relationship of man and woman
+and their children, if any, or a family created by virtue of the birth of a
+child to its biological father and mother."""
GEDCOM_TAG_FAMILY_CHILD = "FAMC"
"""Value: `FAMC`
Identifies the family in which an individual appears as a child."""
+GEDCOM_TAG_FAMILY_FILE = "FAMF"
+"""Value: `FAMF`
+
+Pertaining to, or the name of, a family file. Names stored in a file that are
+assigned to a family for doing temple ordinance work."""
+
GEDCOM_TAG_FAMILY_SPOUSE = "FAMS"
"""Value: `FAMS`
Identifies the family in which an individual appears as a spouse."""
+GEDCOM_TAG_FAX = "FAX"
+"""Value: `FAX`
+
+A FAX telephone number appropriate for sending data facsimiles."""
+
+GEDCOM_TAG_FIRST_COMMUNION = "FCOM"
+"""Value: `FCOM`
+
+A religious rite, the first act of sharing in the Lord's supper as part of
+church worship."""
+
GEDCOM_TAG_FILE = "FILE"
"""Value: `FILE`
-An information storage place that is ordered and arranged for preservation and reference."""
+An information storage place that is ordered and arranged for preservation and
+reference."""
+
+GEDCOM_TAG_PHONETIC = "FONE"
+"""Value: `FONE`
+
+A phonetic variation of a superior text string."""
+
+GEDCOM_TAG_FORMAT = "FORM"
+"""Value: `FORM`
+
+An assigned name given to a consistent format in which information can be
+conveyed."""
+
+GEDCOM_TAG_GEDCOM = "GEDC"
+"""Value: `GEDC`
+
+Information about the use of GEDCOM in a transmission."""
GEDCOM_TAG_GIVEN_NAME = "GIVN"
"""Value: `GIVN`
A given or earned name used for official identification of a person."""
+GEDCOM_TAG_GRADUATION = "GRAD"
+"""Value: `GRAD`
+
+An event of awarding educational diplomas or degrees to individuals."""
+
+GEDCOM_TAG_HEADER = "HEAD"
+"""Value: `HEAD`
+
+Identifies information pertaining to an entire GEDCOM transmission."""
+
GEDCOM_TAG_HUSBAND = "HUSB"
"""Value: `HUSB`
An individual in the family role of a married man or father."""
+GEDCOM_TAG_IDENT_NUMBER = "IDNO"
+"""Value: `IDNO`
+
+A number assigned to identify a person within some significant external system."""
+
+GEDCOM_TAG_IMMIGRATION = "IMMI"
+"""Value: `IMMI`
+
+An event of entering into a new locality witht he intent of residing there."""
+
GEDCOM_TAG_INDIVIDUAL = "INDI"
"""Value: `INDI`
A person."""
+GEDCOM_TAG_LANGUAGE = "LANG"
+"""Value: `LANG`
+
+The name of the language used in a communication or transmission of information."""
+
+GEDCOM_TAG_LATITUDE = "LATI"
+"""Value: `LATI`
+
+A value indicating a coordinate position on a line, plane, or space."""
+
+GEDCOM_TAG_LEGATEE = "LEGA"
+"""Value: `LEGA`
+
+A role of an individual acting as a person receiving a bequest or legal devise."""
+
+GEDCOM_TAG_LONGITUDE = "LONG"
+"""Value: `LONG`
+
+A value indicating a coordinate position on a line, plane, or space."""
+
+GEDCOM_TAG_MAP = "MAP"
+"""Value: `MAP`
+
+Pertains to a representation of measurements usually presented in a graphical
+form."""
+
+GEDCOM_TAG_MARRIAGE_BANN = "MARB"
+"""Value: `MARB`.
+
+An event of an official public notice given that two people intend to marry."""
+
+GEDCOM_TAG_MARR_CONTRACT = "MARC"
+"""Value: `MARC`.
+
+An event of recording a formal agreement of marriage, including the prenuptial
+agreement in which marriage partners reach agreement about the property rights
+of one or both, securing property to their children."""
+
+GEDCOM_TAG_MARR_LICENSE = "MARL"
+"""Value: `MARL`.
+
+An event of obtaining a legal license to marry."""
+
GEDCOM_TAG_MARRIAGE = "MARR"
"""Value: `MARR`.
-A legal, common-law, or customary event of creating a family unit of a man and a woman as husband and wife."""
+A legal, common-law, or customary event of creating a family unit of a man and
+a woman as husband and wife."""
+
+GEDCOM_TAG_MARR_SETTLEMENT = "MARS"
+"""Value: `MARS`.
+
+An event of creating an agreement between two people contemplating marriage,
+at which time they agree to release or modify property rights that would
+otherwise arise from the marriage."""
+
+GEDCOM_TAG_MEDIA = "MEDI"
+"""Value: `MEDI`.
+
+Identifies information about the media or having to do with the medium in which
+information is stored."""
GEDCOM_TAG_NAME = "NAME"
"""Value: `NAME`.
-A word or combination of words used to help identify an individual, title, or other item.
-More than one NAME line should be used for people who were known by multiple names."""
+A word or combination of words used to help identify an individual, title, or
+other item. More than one `NAME` line should be used for people who were known
+by multiple names."""
+
+GEDCOM_TAG_NATIONALITY = "NATI"
+"""Value: `NATI`
+
+The national heritage of an individual."""
+
+GEDCOM_TAG_NATURALIZATION = "NATU"
+"""Value: `NATU`
+
+The event of obtaining citizenship."""
+
+GEDCOM_TAG_CHILDREN_COUNT = "NCHI"
+"""Value: `NCHI`
+
+The number of children that this person is known to be the parent of (all
+marriages) when subordinate to an individual, or that belong to this family
+when subordinate to a `gedcom.tags.GEDCOM_TAG_FAMILY` record."""
+
+GEDCOM_TAG_NICKNAME = "NICK"
+"""Value: `NICK`
+
+A descriptive or familiar that is used instead of, or in addition to, one's
+proper name."""
+
+GEDCOM_TAG_MARRIAGE_COUNT = "NMR"
+"""Value: `NMR`
+
+The number of times this person has participated in a family as a spouse or
+parent."""
+
+GEDCOM_TAG_NOTE = "NOTE"
+"""Value: `NOTE`
+
+Additional information provided by the submitter for understanding the
+enclosing data."""
+
+GEDCOM_TAG_NAME_PREFIX = "NPFX"
+"""Value: `NPFX`
+
+Text which appears on a name line before the given and surname parts of a name.
+i.e. ( Lt. Cmndr. ) Joseph /Allen/ jr. In this example Lt. Cmndr. is considered
+as the name prefix portion."""
+
+GEDCOM_TAG_NAME_SUFFIX = "NSFX"
+"""Value: `NSFX`
+
+Text which appears on a name line after or behind the given and surname parts
+of a name. i.e. Lt. Cmndr. Joseph /Allen/ ( jr. ) In this example jr. is
+considered as the name suffix portion."""
GEDCOM_TAG_OBJECT = "OBJE"
"""Value: `OBJE`
-Pertaining to a grouping of attributes used in describing something. Usually referring to the data required
-to represent a multimedia object, such an audio recording, a photograph of a person, or an image of a document."""
+Pertaining to a grouping of attributes used in describing something. Usually
+referring to the data required to represent a multimedia object, such an audio
+recording, a photograph of a person, or an image of a document."""
GEDCOM_TAG_OCCUPATION = "OCCU"
"""Value: `OCCU`
The type of work or profession of an individual."""
+GEDCOM_TAG_ORDINANCE = "ORDI"
+"""Value: `ORDI`
+
+Pertaining to a religious ordinance in general."""
+
+GEDCOM_TAG_ORDINATION = "ORDN"
+"""Value: `ORDN`
+
+A religious event of receiving authority to act in religious matters."""
+
+GEDCOM_TAG_PAGE = "PAGE"
+"""Value: `PAGE`
+
+A number or description to identify where information can be found in a
+referenced work."""
+
+GEDCOM_TAG_PEDIGREE = "PEDI"
+"""Value: `PEDI`
+
+Information pertaining to an individual to parent lineage chart."""
+
+GEDCOM_TAG_PHONE = "PHON"
+"""Value: `PHON`
+
+A unique number assigned to access a specific telephone."""
+
GEDCOM_TAG_PLACE = "PLAC"
"""Value: `PLAC`
A jurisdictional name to identify the place or location of an event."""
+GEDCOM_TAG_POSTAL_CODE = "POST"
+"""Value: `POST`
+
+A code used by a postal service to identify an area to facilitate mail handling."""
+
GEDCOM_TAG_PRIVATE = "PRIV"
"""Value: `PRIV`
Flag for private address or event."""
+GEDCOM_TAG_PROBATE = "PROB"
+"""Value: `PROB`
+
+An event of judicial determination of the validity of a will. May indicate
+several related court activities over several dates."""
+
+GEDCOM_TAG_PROPERTY = "PROP"
+"""Value: `PROP`
+
+Pertaining to possessions such as real estate or other property of interest."""
+
+GEDCOM_TAG_PUBLICATION = "PUBL"
+"""Value: `PUBL`
+
+Refers to when and/or were a work was published or created."""
+
+GEDCOM_TAG_QUALITY_OF_DATA = "QUAY"
+"""Value: `QUAY`
+
+An assessment of the certainty of the evidence to support the conclusion drawn
+from evidence."""
+
+GEDCOM_TAG_REFERENCE = "REFN"
+"""Value: `REFN`
+
+A description or number used to identify an item for filing, storage, or other
+reference purposes."""
+
+GEDCOM_TAG_RELATIONSHIP = "RELA"
+"""Value: `RELA`
+
+A relationship value between the indicated contexts."""
+
+GEDCOM_TAG_RELIGION = "RELI"
+"""Value: `RELI`
+
+A religious denomination to which a person is affiliated or for which a record
+applies."""
+
+GEDCOM_TAG_REPOSITORY = "REPO"
+"""Value: `REPO`
+
+An institution or person that has the specified item as part of their
+collection(s)."""
+
+GEDCOM_TAG_RESIDENCE = "RESI"
+"""Value: `RESI`
+
+The act of dwelling at a place for a period of time."""
+
+GEDCOM_TAG_RESTRICTION = "RESN"
+"""Value: `RESN`
+
+A processing indicator signifying access to information has been denied or
+otherwise restricted."""
+
+GEDCOM_TAG_RETIREMENT = "RETI"
+"""Value: `RETI`
+
+An event of exiting an occupational relationship with an employer after a
+qualifying time period."""
+
+GEDCOM_TAG_REC_FILE_NUMBER = "RFN"
+"""Value: `RFN`
+
+A permanent number assigned to a record that uniquely identifies it within a
+known file."""
+
+GEDCOM_TAG_REC_ID_NUMBER = "RIN"
+"""Value: `RIN`
+
+A number assigned to a record by an originating automated system that can be
+used by a receiving system to report results pertaining to that record."""
+
+GEDCOM_TAG_ROLE = "ROLE"
+"""Value: `ROLE`
+
+A name given to a role played by an individual in connection with an event."""
+
+GEDCOM_TAG_ROMANIZED = "ROMN"
+"""Value: `ROMN`
+
+A romanized variation of a superior text string."""
+
GEDCOM_TAG_SEX = "SEX"
"""Value: `SEX`
Indicates the sex of an individual--male or female."""
+GEDCOM_TAG_SEALING_CHILD = "SLGC"
+"""Value: `SLGC`
+
+A religious event pertaining to the sealing of a child to his or her parents in
+an LDS temple ceremony."""
+
+GEDCOM_TAG_SEALING_SPOUSE = "SLGS"
+"""Value: `SLGS`
+
+A religious event pertaining to the sealing of a husband and wife in an LDS
+temple ceremony."""
+
GEDCOM_TAG_SOURCE = "SOUR"
"""Value: `SOUR`
The initial or original material from which information was obtained."""
-GEDCOM_TAG_SURNAME = "SURN"
-"""Value: `SURN`
+GEDCOM_TAG_SURN_PREFIX = "SPFX"
+"""Value: `SPFX`
+
+A name piece used as a non-indexing pre-part of a surname."""
+
+GEDCOM_TAG_SOC_SEC_NUMBER = "SSN"
+"""Value: `SSN`
+
+A number assigned by the United States Social Security Administration. Used for
+tax identification purposes."""
+
+GEDCOM_TAG_STATE = "STAE"
+"""Value: `STAE`
+
+A geographical division of a larger jurisdictional area, such as a State within
+the United States of America."""
+
+GEDCOM_TAG_STATUS = "STAT"
+"""Value: `STAT`
+
+An assessment of the state or condition of something."""
+
+GEDCOM_TAG_SUBMITTER = "SUBM"
+"""Value: `SUBM`
+
+An individual or organization who contributes genealogical data to a file or
+transfers it to someone else."""
+
+GEDCOM_TAG_SUBMISSION = "SUBN"
+"""Value: `SUBN`
+
+Pertains to a collection of data issued for processing."""
+
+GEDCOM_TAG_SURNAME = "SURN"
+"""Value: `SURN`
A family name passed on or used by members of a family."""
+GEDCOM_TAG_TEMPLE = "TEMP"
+"""Value: `TEMP`
+
+The name or code that represents the name a temple of the LDS Church."""
+
+GEDCOM_TAG_TEXT = "TEXT"
+"""Value: `TEXT`
+
+The exact wording found in an original source document."""
+
+GEDCOM_TAG_TIME = "TIME"
+"""Value: `TIME`
+
+A time value in a 24-hour clock format, including hours, minutes, and optional
+seconds, separated by a colon (:). Fractions of seconds are shown in decimal
+notation."""
+
+GEDCOM_TAG_TITLE = "TITL"
+"""Value: `TITL`
+
+A description of a specific writing or other work, such as the title of a book
+when used in a source context, or a formal designation used by an individual
+in connection with positions of royalty or other social status, such as Grand
+Duke."""
+
+GEDCOM_TAG_TRAILER = "TRLR"
+"""Value: `TRLR`
+
+At level 0, specifies the end of a GEDCOM transmission."""
+
+GEDCOM_TAG_TYPE = "TYPE"
+"""Value: `TYPE`
+
+A further qualification to the meaning of the associated superior tag. The value
+does not have any computer processing reliability. It is more in the form of a
+short one or two word note that should be displayed any time the associated data
+is displayed."""
+
+GEDCOM_TAG_VERSION = "VERS"
+"""Value: `VERS`
+
+Indicates which version of a product, item, or publication is being used or
+referenced."""
+
GEDCOM_TAG_WIFE = "WIFE"
"""Value: `WIFE`
-An individual in the role as a mother and/or married woman."""
+An individual in the role as a mother and/or married woman."""
+
+GEDCOM_TAG_WWW = "WWW"
+"""Value: `WWW`
+
+World Wide Web home page."""
+
+GEDCOM_TAG_WILL = "WILL"
+"""Value: `WILL`
+
+A legal document treated as an event, by which a person disposes of his or her
+estate, to take effect after death. The event date is the date the will was
+signed while the person was alive. (See also `gedcom.tags.GEDCOM_TAG_PROBATE`)"""
Identifier for a location with the intention of an administrative authority,
+e.g. community identifier.
+
5.5.1 GEDCOM-L Addendum.
+
+
var GEDCOM_PROGRAM_DEFINED_TAG_APID
+
+
Value: _APID
+
Ancestry page identifier. For a citation, points to the page in a Ancestry
+database for the record supporting the citation. For a source record it
+points to the database as a whole.
+
Ancestry.com Extension.
+
+
var GEDCOM_PROGRAM_DEFINED_TAG_DCAUSE
+
+
Value: _DCAUSE
+
Cause of death.
+
+
var GEDCOM_PROGRAM_DEFINED_TAG_DEGREE
+
+
Value: _DEG
+
Degree or recognition of accomplishment received by an individual.
+
+
var GEDCOM_PROGRAM_DEFINED_TAG_DEMOGRAPHIC_DATA
+
+
Value: _DMGD
+
A number of ojects, during an ascertainment, e.g. the count of households.
+
5.5.1 GEDCOM-L Addendum.
+
var GEDCOM_PROGRAM_DEFINED_TAG_FREL
-
Value: _FREL
-
Relationship to a father.
+
Value: _FREL
+
Type of relationship between child and the father in a family.
+
+
var GEDCOM_PROGRAM_DEFINED_TAG_FUNERAL
+
+
Value: _FUN
+
Funeral for an individual.
+
+
var GEDCOM_PROGRAM_DEFINED_TAG_GOVERNMENT
+
+
Value: _GOV
+
The official government id of the object in the Historical Place Register /
+Historic Gazeteer.
The official zip code, called ADDRESS_POSTAL_CODE in the standard.
+
5.5.1 GEDCOM-L Addendum.
+
+
var GEDCOM_PROGRAM_DEFINED_TAG_PREFERRED
+
+
Value: _PREF
+
Indicates a preferred spouse, child or parents.
+
+
var GEDCOM_PROGRAM_DEFINED_TAG_PRIMARY
+
+
Value: _PRIM
+
Primary multimedia object for an individual.
+
+
var GEDCOM_PROGRAM_DEFINED_TAG_RUFNAME
+
+
Value: _RUFNAME
+
An official given name of a German individual used in legal documents.
+
5.5.1 GEDCOM-L Addendum.
+
+
var GEDCOM_PROGRAM_DEFINED_TAG_SCHEMA
+
+
Value: _SCHEMA
+
Schema substructure extension to describe user defined tags.
+
5.5.1 GEDCOM-L Addendum.
+
+
var GEDCOM_PROGRAM_DEFINED_TAG_UUID
+
+
Value: _UID
+
Universal identification number.
+
5.5.1 GEDCOM-L Addendum.
+
+
var GEDCOM_TAG_ABBREVIATION
+
+
Value: ABBR
+
A short name of a title, description, or name.
+
+
var GEDCOM_TAG_ADDRESS
+
+
Value: ADDR
+
The contemporary place, usually required for postal purposes, of an individual,
+a submitter of information, a repository, a business, a school, or a company.
+
+
var GEDCOM_TAG_ADDRESS1
+
+
Value: ADR1
+
The first line of an address.
+
+
var GEDCOM_TAG_ADDRESS2
+
+
Value: ADR2
+
The second line of an address.
+
+
var GEDCOM_TAG_ADDRESS3
+
+
Value: ADR3
+
The third line of an address.
+
+
var GEDCOM_TAG_ADOPTION
+
+
Value: ADOP
+
Pertaining to creation of a child-parent relationship that does not exist
+biologically.
+
+
var GEDCOM_TAG_ADULT_CHRISTENING
+
+
Value: CHRA
+
The religious event (not LDS) of baptizing and/or naming an adult person.
+
+
var GEDCOM_TAG_AFN
+
+
Value: AFN
+
Ancestral File Number, a unique permanent record file number of an individual
+record stored in Ancestral File.
+
+
var GEDCOM_TAG_AGE
+
+
Value: AGE
+
The age of the individual at the time an event occurred, or the age listed in
+the document.
+
+
var GEDCOM_TAG_AGENCY
+
+
Value: AGNC
+
The institution or individual having authority and/or responsibility to manage
+or govern.
+
+
var GEDCOM_TAG_ALIAS
+
+
Value: ALIA
+
An indicator to link different record descriptions of a person who may be the
+same person.
+
+
var GEDCOM_TAG_ANCESTORS
+
+
Value: ANCE
+
Pertaining to forbearers of an individual.
+
+
var GEDCOM_TAG_ANCES_INTEREST
+
+
Value: ANCI
+
Indicates an interest in additional research for ancestors of this individual.
+(See also GEDCOM_TAG_DESCENDANTS_INT)
+
+
var GEDCOM_TAG_ANNULMENT
+
+
Value: ANUL
+
Declaring a marriage void from the beginning (never existed).
+
+
var GEDCOM_TAG_ASSOCIATES
+
+
Value: ASSO
+
An indicator to link friends, neighbors, relatives, or associates of an
+individual.
+
+
var GEDCOM_TAG_AUTHOR
+
+
Value: AUTH
+
The name of the individual who created or compiled information.
+
+
var GEDCOM_TAG_BAPTISM
+
+
Value: BAPM
+
The event of baptism (not LDS), performed in infancy or later.
+
+
var GEDCOM_TAG_BAPTISM_LDS
+
+
Value: BAPL
+
The event of baptism performed at age eight or later by priesthood authority
+of the LDS Church. (See also GEDCOM_TAG_BAPTISM)
+
+
var GEDCOM_TAG_BAR_MITZVAH
+
+
Value: BARM
+
The ceremonial event held when a Jewish boy reaches age 13.
+
+
var GEDCOM_TAG_BAS_MITZVAH
+
+
Value: BASM
+
The ceremonial event held when a Jewish girl reaches age 13, also known as
+Bat Mitzvah.
var GEDCOM_TAG_BIRTH
-
Value: BIRT
-
The event of entering into life.
+
Value: BIRT
+
The event of entering into life.
+
+
var GEDCOM_TAG_BLESSING
+
+
Value: BLES
+
A religious event of bestowing divine care or intercession. Sometimes given
+in connection with a naming ceremony.
var GEDCOM_TAG_BURIAL
-
Value: BURI
-
The event of the proper disposing of the mortal remains of a deceased person.
+
Value: BURI
+
The event of the proper disposing of the mortal remains of a deceased person.
+
+
var GEDCOM_TAG_CALL_NUMBER
+
+
Value: CALN
+
The number used by a repository to identify the specific items in its
+collections.
+
+
var GEDCOM_TAG_CASTE
+
+
Value: CAST
+
The name of an individual's rank or status in society, based on racial or
+religious differences, or differences in wealth, inherited rank, profession,
+occupation, etc.
+
+
var GEDCOM_TAG_CAUSE
+
+
Value: CAUS
+
A description of the cause of the associated event or fact, such as the cause
+of death.
var GEDCOM_TAG_CENSUS
-
Value: CENS.
-
The event of the periodic count of the population for a designated locality, such as a national or state Census.
+
Value: CENS.
+
The event of the periodic count of the population for a designated locality,
+such as a national or state Census.
var GEDCOM_TAG_CHANGE
-
Value: CHAN
+
Value: CHAN
Indicates a change, correction, or modification. Typically used in connection
-with a GEDCOM_TAG_DATE to specify when a change in information occurred.
+with a GEDCOM_TAG_DATE to specify when a change in information
+occurred.
+
+
var GEDCOM_TAG_CHARACTER
+
+
Value: CHAR
+
An indicator of the character set used in writing this automated information.
var GEDCOM_TAG_CHILD
-
Value: CHIL
-
The natural, adopted, or sealed (LDS) child of a father and a mother.
+
Value: CHIL
+
The natural, adopted, or sealed (LDS) child of a father and a mother.
+
+
var GEDCOM_TAG_CHILDREN_COUNT
+
+
Value: NCHI
+
The number of children that this person is known to be the parent of (all
+marriages) when subordinate to an individual, or that belong to this family
+when subordinate to a GEDCOM_TAG_FAMILY record.
+
+
var GEDCOM_TAG_CHRISTENING
+
+
Value: CHR
+
The religious event (not LDS) of baptizing and/or naming a child.
+
+
var GEDCOM_TAG_CITY
+
+
Value: CITY
+
A lower level jurisdictional unit. Normally an incorporated municipal unit.
var GEDCOM_TAG_CONCATENATION
-
Value: CONC
-
An indicator that additional data belongs to the superior value. The information from the CONC value is to
-be connected to the value of the superior preceding line without a space and without a carriage return and/or
-new line character. Values that are split for a CONC tag must always be split at a non-space. If the value is
-split on a space the space will be lost when concatenation takes place. This is because of the treatment that
-spaces get as a GEDCOM delimiter, many GEDCOM values are trimmed of trailing spaces and some systems look for
-the first non-space starting after the tag to determine the beginning of the value.
+
Value: CONC
+
An indicator that additional data belongs to the superior value. The information
+from the CONC value is to be connected to the value of the superior preceding
+line without a space and without a carriage return and/or new line character.
+Values that are split for a CONC tag must always be split at a non-space. If
+the value is split on a space the space will be lost when concatenation takes
+place. This is because of the treatment that spaces get as a GEDCOM delimiter,
+many GEDCOM values are trimmed of trailing spaces and some systems look for
+the first non-space starting after the tag to determine the beginning of the
+value.
+
+
var GEDCOM_TAG_CONFIRMATION
+
+
Value: CONF
+
The religious event (not LDS) of conferring the gift of the Holy Ghost and,
+among protestants, full church membership.
+
+
var GEDCOM_TAG_CONFIRMATION_L
+
+
Value: CONL
+
The religious event by which a person receives membership in the LDS Church.
var GEDCOM_TAG_CONTINUED
-
Value: CONT
-
An indicator that additional data belongs to the superior value. The information from the CONT value is to be
-connected to the value of the superior preceding line with a carriage return and/or new line character.
-Leading spaces could be important to the formatting of the resultant text. When importing values from CONT lines
-the reader should assume only one delimiter character following the CONT tag. Assume that the rest of the leading
-spaces are to be a part of the value.
+
Value: CONT
+
An indicator that additional data belongs to the superior value. The information
+from the CONT value is to be connected to the value of the superior preceding
+line with a carriage return and/or new line character. Leading spaces could be
+important to the formatting of the resultant text. When importing values from
+CONT lines the reader should assume only one delimiter character following
+the CONT tag. Assume that the rest of the leading spaces are to be a part
+of the value.
+
+
var GEDCOM_TAG_COPYRIGHT
+
+
Value: COPR
+
A statement that accompanies data to protect it from unlawful duplication
+and distribution.
+
+
var GEDCOM_TAG_CORPORATE
+
+
Value: CORP
+
A name of an institution, agency, corporation, or company.
+
+
var GEDCOM_TAG_COUNTRY
+
+
Value: CTRY
+
The name or code of a country.
+
+
var GEDCOM_TAG_CREMATION
+
+
Value: CREM
+
Disposal of the remains of a person's body by fire.
+
+
var GEDCOM_TAG_DATA
+
+
Value: DATA
+
Pertaining to stored automation information.
var GEDCOM_TAG_DATE
-
Value: DATE
-
The time of an event in a calendar format.
+
Value: DATE
+
The time of an event in a calendar format.
var GEDCOM_TAG_DEATH
-
Value: DEAT
-
The event when mortal life terminates.
+
Value: DEAT
+
The event when mortal life terminates.
+
+
var GEDCOM_TAG_DESCENDANTS
+
+
Value: DESC
+
Pertaining to offspring of an individual.
+
+
var GEDCOM_TAG_DESCENDANTS_INT
+
+
Value: DESI
+
Indicates an interest in research to identify additional descendants of this
+individual. (See also GEDCOM_TAG_ANCES_INTEREST)
+
+
var GEDCOM_TAG_DESTINATION
+
+
Value: DEST
+
A system receiving data.
+
+
var GEDCOM_TAG_DIVORCE
+
+
Value: DIV
+
The event of disolving a marriage through civil action.
+
+
var GEDCOM_TAG_DIVORCE_FILED
+
+
Value: DIVF
+
An event of filing for a divorce by a spouse.
+
+
var GEDCOM_TAG_EDUCATION
+
+
Value: EDUC
+
Indicator of a level of education attained.
+
+
var GEDCOM_TAG_EMAIL
+
+
Value: EMAIL
+
An electronic address that can be used for contact such as an email address.
+
+
var GEDCOM_TAG_EMIGRATION
+
+
Value: EMIG
+
An event of leaving one's homeland with the intent of residing elsewhere.
+
+
var GEDCOM_TAG_ENDOWMENT
+
+
Value: ENDL
+
A religious event where an endowment ordinance for an individual was performed
+by priesthood authority in an LDS temple.
+
+
var GEDCOM_TAG_ENGAGEMENT
+
+
Value: ENGA
+
An event of recording or announcing an agreement between two people to become
+married.
+
+
var GEDCOM_TAG_EVENT
+
+
Value: EVEN
+
A noteworthy happening related to an individual, a group, or an organization.
+
+
var GEDCOM_TAG_FACT
+
+
Value: FACT
+
Pertaining to a noteworthy attribute or fact concerning an individual, a group,
+or an organization. A FACT structure is usually qualified or classified by a
+subordinate use of the GEDCOM_TAG_TYPE tag.
var GEDCOM_TAG_FAMILY
-
Value: FAM.
-
Identifies a legal, common law, or other customary relationship of man and woman and their children,
-if any, or a family created by virtue of the birth of a child to its biological father and mother.
+
Value: FAM.
+
Identifies a legal, common law, or other customary relationship of man and woman
+and their children, if any, or a family created by virtue of the birth of a
+child to its biological father and mother.
var GEDCOM_TAG_FAMILY_CHILD
-
Value: FAMC
-
Identifies the family in which an individual appears as a child.
+
Value: FAMC
+
Identifies the family in which an individual appears as a child.
+
+
var GEDCOM_TAG_FAMILY_FILE
+
+
Value: FAMF
+
Pertaining to, or the name of, a family file. Names stored in a file that are
+assigned to a family for doing temple ordinance work.
var GEDCOM_TAG_FAMILY_SPOUSE
-
Value: FAMS
-
Identifies the family in which an individual appears as a spouse.
+
Value: FAMS
+
Identifies the family in which an individual appears as a spouse.
+
+
var GEDCOM_TAG_FAX
+
+
Value: FAX
+
A FAX telephone number appropriate for sending data facsimiles.
var GEDCOM_TAG_FILE
-
Value: FILE
-
An information storage place that is ordered and arranged for preservation and reference.
+
Value: FILE
+
An information storage place that is ordered and arranged for preservation and
+reference.
+
+
var GEDCOM_TAG_FIRST_COMMUNION
+
+
Value: FCOM
+
A religious rite, the first act of sharing in the Lord's supper as part of
+church worship.
+
+
var GEDCOM_TAG_FORMAT
+
+
Value: FORM
+
An assigned name given to a consistent format in which information can be
+conveyed.
+
+
var GEDCOM_TAG_GEDCOM
+
+
Value: GEDC
+
Information about the use of GEDCOM in a transmission.
var GEDCOM_TAG_GIVEN_NAME
-
Value: GIVN
-
A given or earned name used for official identification of a person.
+
Value: GIVN
+
A given or earned name used for official identification of a person.
+
+
var GEDCOM_TAG_GRADUATION
+
+
Value: GRAD
+
An event of awarding educational diplomas or degrees to individuals.
+
+
var GEDCOM_TAG_HEADER
+
+
Value: HEAD
+
Identifies information pertaining to an entire GEDCOM transmission.
var GEDCOM_TAG_HUSBAND
-
Value: HUSB
-
An individual in the family role of a married man or father.
+
Value: HUSB
+
An individual in the family role of a married man or father.
+
+
var GEDCOM_TAG_IDENT_NUMBER
+
+
Value: IDNO
+
A number assigned to identify a person within some significant external system.
+
+
var GEDCOM_TAG_IMMIGRATION
+
+
Value: IMMI
+
An event of entering into a new locality witht he intent of residing there.
var GEDCOM_TAG_INDIVIDUAL
-
Value: INDI
-
A person.
+
Value: INDI
+
A person.
+
+
var GEDCOM_TAG_LANGUAGE
+
+
Value: LANG
+
The name of the language used in a communication or transmission of information.
+
+
var GEDCOM_TAG_LATITUDE
+
+
Value: LATI
+
A value indicating a coordinate position on a line, plane, or space.
+
+
var GEDCOM_TAG_LEGATEE
+
+
Value: LEGA
+
A role of an individual acting as a person receiving a bequest or legal devise.
+
+
var GEDCOM_TAG_LONGITUDE
+
+
Value: LONG
+
A value indicating a coordinate position on a line, plane, or space.
+
+
var GEDCOM_TAG_MAP
+
+
Value: MAP
+
Pertains to a representation of measurements usually presented in a graphical
+form.
var GEDCOM_TAG_MARRIAGE
-
Value: MARR.
-
A legal, common-law, or customary event of creating a family unit of a man and a woman as husband and wife.
+
Value: MARR.
+
A legal, common-law, or customary event of creating a family unit of a man and
+a woman as husband and wife.
+
+
var GEDCOM_TAG_MARRIAGE_BANN
+
+
Value: MARB.
+
An event of an official public notice given that two people intend to marry.
+
+
var GEDCOM_TAG_MARRIAGE_COUNT
+
+
Value: NMR
+
The number of times this person has participated in a family as a spouse or
+parent.
+
+
var GEDCOM_TAG_MARR_CONTRACT
+
+
Value: MARC.
+
An event of recording a formal agreement of marriage, including the prenuptial
+agreement in which marriage partners reach agreement about the property rights
+of one or both, securing property to their children.
+
+
var GEDCOM_TAG_MARR_LICENSE
+
+
Value: MARL.
+
An event of obtaining a legal license to marry.
+
+
var GEDCOM_TAG_MARR_SETTLEMENT
+
+
Value: MARS.
+
An event of creating an agreement between two people contemplating marriage,
+at which time they agree to release or modify property rights that would
+otherwise arise from the marriage.
+
+
var GEDCOM_TAG_MEDIA
+
+
Value: MEDI.
+
Identifies information about the media or having to do with the medium in which
+information is stored.
var GEDCOM_TAG_NAME
-
Value: NAME.
-
A word or combination of words used to help identify an individual, title, or other item.
-More than one NAME line should be used for people who were known by multiple names.
+
Value: NAME.
+
A word or combination of words used to help identify an individual, title, or
+other item. More than one NAME line should be used for people who were known
+by multiple names.
+
+
var GEDCOM_TAG_NAME_PREFIX
+
+
Value: NPFX
+
Text which appears on a name line before the given and surname parts of a name.
+i.e. ( Lt. Cmndr. ) Joseph /Allen/ jr. In this example Lt. Cmndr. is considered
+as the name prefix portion.
+
+
var GEDCOM_TAG_NAME_SUFFIX
+
+
Value: NSFX
+
Text which appears on a name line after or behind the given and surname parts
+of a name. i.e. Lt. Cmndr. Joseph /Allen/ ( jr. ) In this example jr. is
+considered as the name suffix portion.
+
+
var GEDCOM_TAG_NATIONALITY
+
+
Value: NATI
+
The national heritage of an individual.
+
+
var GEDCOM_TAG_NATURALIZATION
+
+
Value: NATU
+
The event of obtaining citizenship.
+
+
var GEDCOM_TAG_NICKNAME
+
+
Value: NICK
+
A descriptive or familiar that is used instead of, or in addition to, one's
+proper name.
+
+
var GEDCOM_TAG_NOTE
+
+
Value: NOTE
+
Additional information provided by the submitter for understanding the
+enclosing data.
var GEDCOM_TAG_OBJECT
-
Value: OBJE
-
Pertaining to a grouping of attributes used in describing something. Usually referring to the data required
-to represent a multimedia object, such an audio recording, a photograph of a person, or an image of a document.
+
Value: OBJE
+
Pertaining to a grouping of attributes used in describing something. Usually
+referring to the data required to represent a multimedia object, such an audio
+recording, a photograph of a person, or an image of a document.
var GEDCOM_TAG_OCCUPATION
-
Value: OCCU
-
The type of work or profession of an individual.
+
Value: OCCU
+
The type of work or profession of an individual.
+
+
var GEDCOM_TAG_ORDINANCE
+
+
Value: ORDI
+
Pertaining to a religious ordinance in general.
+
+
var GEDCOM_TAG_ORDINATION
+
+
Value: ORDN
+
A religious event of receiving authority to act in religious matters.
+
+
var GEDCOM_TAG_PAGE
+
+
Value: PAGE
+
A number or description to identify where information can be found in a
+referenced work.
+
+
var GEDCOM_TAG_PEDIGREE
+
+
Value: PEDI
+
Information pertaining to an individual to parent lineage chart.
+
+
var GEDCOM_TAG_PHONE
+
+
Value: PHON
+
A unique number assigned to access a specific telephone.
+
+
var GEDCOM_TAG_PHONETIC
+
+
Value: FONE
+
A phonetic variation of a superior text string.
+
+
var GEDCOM_TAG_PHY_DESCRIPTION
+
+
Value: DSCR
+
The physical characteristics of a person, place, or thing.
var GEDCOM_TAG_PLACE
-
Value: PLAC
-
A jurisdictional name to identify the place or location of an event.
+
Value: PLAC
+
A jurisdictional name to identify the place or location of an event.
+
+
var GEDCOM_TAG_POSTAL_CODE
+
+
Value: POST
+
A code used by a postal service to identify an area to facilitate mail handling.
var GEDCOM_TAG_PRIVATE
-
Value: PRIV
-
Flag for private address or event.
+
Value: PRIV
+
Flag for private address or event.
+
+
var GEDCOM_TAG_PROBATE
+
+
Value: PROB
+
An event of judicial determination of the validity of a will. May indicate
+several related court activities over several dates.
+
+
var GEDCOM_TAG_PROPERTY
+
+
Value: PROP
+
Pertaining to possessions such as real estate or other property of interest.
+
+
var GEDCOM_TAG_PUBLICATION
+
+
Value: PUBL
+
Refers to when and/or were a work was published or created.
+
+
var GEDCOM_TAG_QUALITY_OF_DATA
+
+
Value: QUAY
+
An assessment of the certainty of the evidence to support the conclusion drawn
+from evidence.
+
+
var GEDCOM_TAG_REC_FILE_NUMBER
+
+
Value: RFN
+
A permanent number assigned to a record that uniquely identifies it within a
+known file.
+
+
var GEDCOM_TAG_REC_ID_NUMBER
+
+
Value: RIN
+
A number assigned to a record by an originating automated system that can be
+used by a receiving system to report results pertaining to that record.
+
+
var GEDCOM_TAG_REFERENCE
+
+
Value: REFN
+
A description or number used to identify an item for filing, storage, or other
+reference purposes.
+
+
var GEDCOM_TAG_RELATIONSHIP
+
+
Value: RELA
+
A relationship value between the indicated contexts.
+
+
var GEDCOM_TAG_RELIGION
+
+
Value: RELI
+
A religious denomination to which a person is affiliated or for which a record
+applies.
+
+
var GEDCOM_TAG_REPOSITORY
+
+
Value: REPO
+
An institution or person that has the specified item as part of their
+collection(s).
+
+
var GEDCOM_TAG_RESIDENCE
+
+
Value: RESI
+
The act of dwelling at a place for a period of time.
+
+
var GEDCOM_TAG_RESTRICTION
+
+
Value: RESN
+
A processing indicator signifying access to information has been denied or
+otherwise restricted.
+
+
var GEDCOM_TAG_RETIREMENT
+
+
Value: RETI
+
An event of exiting an occupational relationship with an employer after a
+qualifying time period.
+
+
var GEDCOM_TAG_ROLE
+
+
Value: ROLE
+
A name given to a role played by an individual in connection with an event.
+
+
var GEDCOM_TAG_ROMANIZED
+
+
Value: ROMN
+
A romanized variation of a superior text string.
+
+
var GEDCOM_TAG_SEALING_CHILD
+
+
Value: SLGC
+
A religious event pertaining to the sealing of a child to his or her parents in
+an LDS temple ceremony.
+
+
var GEDCOM_TAG_SEALING_SPOUSE
+
+
Value: SLGS
+
A religious event pertaining to the sealing of a husband and wife in an LDS
+temple ceremony.
var GEDCOM_TAG_SEX
-
Value: SEX
-
Indicates the sex of an individual–male or female.
+
Value: SEX
+
Indicates the sex of an individual–male or female.
+
+
var GEDCOM_TAG_SOC_SEC_NUMBER
+
+
Value: SSN
+
A number assigned by the United States Social Security Administration. Used for
+tax identification purposes.
var GEDCOM_TAG_SOURCE
-
Value: SOUR
-
The initial or original material from which information was obtained.
+
Value: SOUR
+
The initial or original material from which information was obtained.
+
+
var GEDCOM_TAG_STATE
+
+
Value: STAE
+
A geographical division of a larger jurisdictional area, such as a State within
+the United States of America.
+
+
var GEDCOM_TAG_STATUS
+
+
Value: STAT
+
An assessment of the state or condition of something.
+
+
var GEDCOM_TAG_SUBMISSION
+
+
Value: SUBN
+
Pertains to a collection of data issued for processing.
+
+
var GEDCOM_TAG_SUBMITTER
+
+
Value: SUBM
+
An individual or organization who contributes genealogical data to a file or
+transfers it to someone else.
var GEDCOM_TAG_SURNAME
-
Value: SURN
-
A family name passed on or used by members of a family.
+
Value: SURN
+
A family name passed on or used by members of a family.
+
+
var GEDCOM_TAG_SURN_PREFIX
+
+
Value: SPFX
+
A name piece used as a non-indexing pre-part of a surname.
+
+
var GEDCOM_TAG_TEMPLE
+
+
Value: TEMP
+
The name or code that represents the name a temple of the LDS Church.
+
+
var GEDCOM_TAG_TEXT
+
+
Value: TEXT
+
The exact wording found in an original source document.
+
+
var GEDCOM_TAG_TIME
+
+
Value: TIME
+
A time value in a 24-hour clock format, including hours, minutes, and optional
+seconds, separated by a colon (:). Fractions of seconds are shown in decimal
+notation.
+
+
var GEDCOM_TAG_TITLE
+
+
Value: TITL
+
A description of a specific writing or other work, such as the title of a book
+when used in a source context, or a formal designation used by an individual
+in connection with positions of royalty or other social status, such as Grand
+Duke.
+
+
var GEDCOM_TAG_TRAILER
+
+
Value: TRLR
+
At level 0, specifies the end of a GEDCOM transmission.
+
+
var GEDCOM_TAG_TYPE
+
+
Value: TYPE
+
A further qualification to the meaning of the associated superior tag. The value
+does not have any computer processing reliability. It is more in the form of a
+short one or two word note that should be displayed any time the associated data
+is displayed.
+
+
var GEDCOM_TAG_VERSION
+
+
Value: VERS
+
Indicates which version of a product, item, or publication is being used or
+referenced.
var GEDCOM_TAG_WIFE
-
Value: WIFE
-
An individual in the role as a mother and/or married woman.
+
Value: WIFE
+
An individual in the role as a mother and/or married woman.
+
+
var GEDCOM_TAG_WILL
+
+
Value: WILL
+
A legal document treated as an event, by which a person disposes of his or her
+estate, to take effect after death. The event date is the date the will was
+signed while the person was alive. (See also GEDCOM_TAG_PROBATE)
diff --git a/gedcom/__init__.py b/gedcom/__init__.py
index 386a74b..65ea462 100644
--- a/gedcom/__init__.py
+++ b/gedcom/__init__.py
@@ -34,8 +34,14 @@
__all__ = [
# Subpackages
"element",
+ "subparsers",
# Modules
+ "errors",
"helpers",
+ "detect",
"parser",
+ "reader",
+ "records",
+ "standards",
"tags"
]
diff --git a/gedcom/detect.py b/gedcom/detect.py
new file mode 100644
index 0000000..d79116c
--- /dev/null
+++ b/gedcom/detect.py
@@ -0,0 +1,137 @@
+# -*- coding: utf-8 -*-
+
+# Python GEDCOM Parser
+#
+# Copyright (C) 2020 Christopher Horn (cdhorn at embarqmail dot com)
+# Copyright (C) 2018 Damon Brodie (damon.brodie at gmail.com)
+# Copyright (C) 2018-2019 Nicklas Reincke (contact at reynke.com)
+# Copyright (C) 2016 Andreas Oberritter
+# Copyright (C) 2012 Madeleine Price Ball
+# Copyright (C) 2005 Daniel Zappala (zappala at cs.byu.edu)
+# Copyright (C) 2005 Brigham Young University
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Further information about the license: http://www.gnu.org/licenses/gpl-2.0.html
+
+"""
+Module containing functions for detecting GEDCOM file encoding and version.
+"""
+
+from typing import Tuple
+import chardet
+import ansel
+
+import gedcom.tags as tags
+import gedcom.standards as standards
+from gedcom.errors import GedcomFormatViolationError
+from gedcom.errors import GedcomCharacterSetUnsupportedError
+
+ansel.register()
+
+
+def __validate_encoding(file_path, codec):
+ """Check the encoding is compatible with the encoding as reported by the
+ `gedcom.tags.GEDCOM_TAG_CHARACTER` header tag.
+ """
+ with open(file_path, 'r', encoding=codec) as gedcom_data:
+ for line in gedcom_data:
+ if tags.GEDCOM_TAG_CHARACTER in line:
+ character_set = line.split(' ')[2].lower().strip()
+ break
+
+ if character_set == 'ansel' and codec == 'gedcom':
+ return
+
+ if character_set == 'ascii' and codec == 'utf-8':
+ return
+
+ if character_set not in codec:
+ errmsg = "A " + codec + " encoding was detected but the GEDCOM reports using " + \
+ "a " + character_set + " encoding.\n" + \
+ "Processing aborted as unsure how to properly proceed.\n" + \
+ "See: {0}".format(standards.GEDCOM_5_5_1)
+ raise GedcomCharacterSetUnsupportedError(errmsg)
+
+
+def get_encoding(file_path: str) -> str:
+ """Probe a GEDCOM file to determine the encoding and validate it against the encoding
+ as reported in the `HEADER` record by the `gedcom.tags.GEDCOM_TAG_CHARACTER` tag.
+
+ Returns: codec
+ """
+ with open(file_path, 'rb') as gedcom_data:
+ sample_data = gedcom_data.read(262144)
+
+ # Note chardet reports Ansel as ISO-8859-1 or ISO-8859-2 at this time
+ # depending on sample size, and could be making a faulty assumption here
+ # by treating it as Ansel. The ansel module supports both ansel and a
+ # gedcom codec with some gedcom specific extensions so we use that.
+ codec = 'unknown'
+ probe = chardet.detect(sample_data)
+ if probe['encoding'] in ['UTF-8', 'UTF-8-SIG']:
+ codec = 'utf-8-sig'
+ elif probe['encoding'] == 'UTF-16':
+ codec = 'utf-16'
+ elif probe['encoding'] == 'ASCII':
+ codec = 'ascii'
+ elif probe['encoding'] == 'ANSEL':
+ codec = 'ansel'
+ elif 'ISO-8859' in probe['encoding']:
+ codec = 'gedcom'
+
+ if codec == 'unknown':
+ errmsg = "Unable to properly identify a supported GEDCOM character encoding for" + \
+ "the file.\nSee: {0}".format(standards.GEDCOM_5_5_1)
+ raise GedcomCharacterSetUnsupportedError(errmsg)
+
+ __validate_encoding(file_path, codec)
+ return codec
+
+
+def get_version(file_path: str, codec: str) -> Tuple[str, str, str]:
+ """Probe a GEDCOM file to identify the version of the standard used as some reported 5.5
+ files are really 5.5.1.
+
+ Returns: probed version, reported version, reported format
+ """
+ in_gedc_tag = False
+ gedcom_version = None
+ gedcom_format = None
+ with open(file_path, 'r', encoding=codec) as gedcom_data:
+ for line in gedcom_data:
+ if '1 GEDC' in line:
+ in_gedc_tag = True
+ continue
+ if in_gedc_tag:
+ if '2 VERS' in line:
+ gedcom_version = line.split(' ')[2].strip()
+ continue
+ if '2 FORM' in line:
+ gedcom_format = line.split(' ')[2].strip()
+ break
+
+ if gedcom_version is None or gedcom_format is None:
+ errmsg = "Malformed GEDCOM file, the required version number or format were" + \
+ " not found as expected.\nSee: {0}".format(standards.GEDCOM_5_5_1)
+ raise GedcomFormatViolationError(errmsg)
+
+ probed_version = gedcom_version
+
+ # UTF was added in the 5.5.1 specification
+ if gedcom_version == '5.5' and 'utf' in codec:
+ probed_version = gedcom_version
+
+ return probed_version, gedcom_version, gedcom_format
diff --git a/gedcom/element/__init__.py b/gedcom/element/__init__.py
index 34eaac5..4360a26 100644
--- a/gedcom/element/__init__.py
+++ b/gedcom/element/__init__.py
@@ -33,8 +33,13 @@
__all__ = [
"element",
"family",
- "file",
+ "header",
"individual",
+ "note",
"object",
- "root"
+ "repository",
+ "root",
+ "source",
+ "submission",
+ "submitter"
]
diff --git a/gedcom/element/element.py b/gedcom/element/element.py
index 3428e3c..c62b1af 100644
--- a/gedcom/element/element.py
+++ b/gedcom/element/element.py
@@ -26,18 +26,20 @@
# Further information about the license: http://www.gnu.org/licenses/gpl-2.0.html
"""
-Base GEDCOM element
+Base GEDCOM element.
"""
from sys import version_info
+from typing import List
+
from gedcom.helpers import deprecated
import gedcom.tags
class Element(object):
- """GEDCOM element
+ """GEDCOM element.
- Each line in a GEDCOM file is an element with the format
+ Each line in a GEDCOM file is an element with the format:
`level [pointer] tag [value]`
@@ -62,7 +64,8 @@ class Element(object):
Tags available to an element are seen here: `gedcom.tags`
"""
- def __init__(self, level, pointer, tag, value, crlf="\n", multi_line=True):
+ def __init__(self, level: int, pointer: str, tag: str, value: str,
+ crlf: str = "\n", multi_line: bool = True):
# basic element info
self.__level = level
self.__pointer = pointer
@@ -77,39 +80,33 @@ def __init__(self, level, pointer, tag, value, crlf="\n", multi_line=True):
if multi_line:
self.set_multi_line_value(value)
- def get_level(self):
- """Returns the level of this element from within the GEDCOM file
- :rtype: int
+ def get_level(self) -> int:
+ """Returns the level of this element from within the GEDCOM file.
"""
return self.__level
- def get_pointer(self):
- """Returns the pointer of this element from within the GEDCOM file
- :rtype: str
+ def get_pointer(self) -> str:
+ """Returns the pointer of this element from within the GEDCOM file.
"""
return self.__pointer
- def get_tag(self):
- """Returns the tag of this element from within the GEDCOM file
- :rtype: str
+ def get_tag(self) -> str:
+ """Returns the tag of this element from within the GEDCOM file.
"""
return self.__tag
- def get_value(self):
- """Return the value of this element from within the GEDCOM file
- :rtype: str
+ def get_value(self) -> str:
+ """Return the value of this element from within the GEDCOM file.
"""
return self.__value
- def set_value(self, value):
- """Sets the value of this element
- :type value: str
+ def set_value(self, value: str):
+ """Sets the value of this element.
"""
self.__value = value
- def get_multi_line_value(self):
- """Returns the value of this element including concatenations or continuations
- :rtype: str
+ def get_multi_line_value(self) -> str:
+ """Returns the value of this element including concatenations or continuations.
"""
result = self.get_value()
last_crlf = self.__crlf
@@ -123,17 +120,14 @@ def get_multi_line_value(self):
last_crlf = element.__crlf
return result
- def __available_characters(self):
+ def __available_characters(self) -> int:
"""Get the number of available characters of the elements original string
- :rtype: int
"""
element_characters = len(self.to_gedcom_string())
return 0 if element_characters > 255 else 255 - element_characters
- def __line_length(self, line):
- """@TODO Write docs.
- :type line: str
- :rtype: int
+ def __line_length(self, line: str) -> int:
+ """Return line length.
"""
total_characters = len(line)
available_characters = self.__available_characters()
@@ -146,40 +140,36 @@ def __line_length(self, line):
return available_characters
return available_characters - spaces
- def __set_bounded_value(self, value):
+ def __set_bounded_value(self, value: str) -> int:
"""@TODO Write docs.
- :type value: str
- :rtype: int
"""
line_length = self.__line_length(value)
self.set_value(value[:line_length])
return line_length
- def __add_bounded_child(self, tag, value):
+ def __add_bounded_child(self, tag: str, value: str) -> int:
"""@TODO Write docs.
- :type tag: str
- :type value: str
- :rtype: int
"""
child = self.new_child_element(tag)
return child.__set_bounded_value(value)
- def __add_concatenation(self, string):
+ def __add_concatenation(self, string: str):
"""@TODO Write docs.
- :rtype: str
"""
index = 0
size = len(string)
while index < size:
index += self.__add_bounded_child(gedcom.tags.GEDCOM_TAG_CONCATENATION, string[index:])
- def set_multi_line_value(self, value):
- """Sets the value of this element, adding concatenation and continuation lines when necessary
- :type value: str
+ def set_multi_line_value(self, value: str):
+ """Sets the value of this element, adding concatenation and continuation lines
+ when necessary.
"""
self.set_value('')
self.get_child_elements()[:] = [child for child in self.get_child_elements() if
- child.get_tag() not in (gedcom.tags.GEDCOM_TAG_CONCATENATION, gedcom.tags.GEDCOM_TAG_CONTINUED)]
+ child.get_tag() not in
+ (gedcom.tags.GEDCOM_TAG_CONCATENATION,
+ gedcom.tags.GEDCOM_TAG_CONTINUED)]
lines = value.splitlines()
if lines:
@@ -191,79 +181,91 @@ def set_multi_line_value(self, value):
n = self.__add_bounded_child(gedcom.tags.GEDCOM_TAG_CONTINUED, line)
self.__add_concatenation(line[n:])
- def get_child_elements(self):
- """Returns the direct child elements of this element
- :rtype: list of Element
+ def get_child_elements(self) -> List['Element']:
+ """Returns the direct child elements of this element.
"""
return self.__children
- def new_child_element(self, tag, pointer="", value=""):
- """Creates and returns a new child element of this element
-
- :type tag: str
- :type pointer: str
- :type value: str
- :rtype: Element
+ def new_child_element(self, tag: str, pointer: str = "",
+ value: str = "") -> 'Element':
+ """Creates and returns a new child element of this element.
"""
from gedcom.element.family import FamilyElement
- from gedcom.element.file import FileElement
from gedcom.element.individual import IndividualElement
+ from gedcom.element.note import NoteElement
from gedcom.element.object import ObjectElement
+ from gedcom.element.repository import RepositoryElement
+ from gedcom.element.source import SourceElement
+ from gedcom.element.submitter import SubmitterElement
+ from gedcom.element.submission import SubmissionElement
+ from gedcom.element.header import HeaderElement
# Differentiate between the type of the new child element
if tag == gedcom.tags.GEDCOM_TAG_FAMILY:
- child_element = FamilyElement(self.get_level() + 1, pointer, tag, value, self.__crlf)
- elif tag == gedcom.tags.GEDCOM_TAG_FILE:
- child_element = FileElement(self.get_level() + 1, pointer, tag, value, self.__crlf)
+ child_element = FamilyElement(self.get_level() + 1, pointer, tag,
+ value, self.__crlf)
elif tag == gedcom.tags.GEDCOM_TAG_INDIVIDUAL:
- child_element = IndividualElement(self.get_level() + 1, pointer, tag, value, self.__crlf)
+ child_element = IndividualElement(self.get_level() + 1, pointer, tag,
+ value, self.__crlf)
+ elif tag == gedcom.tags.GEDCOM_TAG_NOTE:
+ child_element = NoteElement(self.get_level() + 1, pointer, tag,
+ value, self.__crlf)
elif tag == gedcom.tags.GEDCOM_TAG_OBJECT:
- child_element = ObjectElement(self.get_level() + 1, pointer, tag, value, self.__crlf)
+ child_element = ObjectElement(self.get_level() + 1, pointer, tag,
+ value, self.__crlf)
+ elif tag == gedcom.tags.GEDCOM_TAG_REPOSITORY:
+ child_element = RepositoryElement(self.get_level() + 1, pointer, tag,
+ value, self.__crlf)
+ elif tag == gedcom.tags.GEDCOM_TAG_SOURCE:
+ child_element = SourceElement(self.get_level() + 1, pointer, tag,
+ value, self.__crlf)
+ elif tag == gedcom.tags.GEDCOM_TAG_SUBMITTER:
+ child_element = SubmitterElement(self.get_level() + 1, pointer, tag,
+ value, self.__crlf)
+ elif tag == gedcom.tags.GEDCOM_TAG_SUBMISSION:
+ child_element = SubmissionElement(self.get_level() + 1, pointer, tag,
+ value, self.__crlf)
+ elif tag == gedcom.tags.GEDCOM_TAG_HEADER:
+ child_element = HeaderElement(self.get_level() + 1, pointer, tag,
+ value, self.__crlf)
else:
- child_element = Element(self.get_level() + 1, pointer, tag, value, self.__crlf)
+ child_element = Element(self.get_level() + 1, pointer, tag,
+ value, self.__crlf)
self.add_child_element(child_element)
return child_element
- def add_child_element(self, element):
- """Adds a child element to this element
-
- :type element: Element
+ def add_child_element(self, element: 'Element'):
+ """Adds a child element to this element.
"""
self.get_child_elements().append(element)
element.set_parent_element(self)
return element
- def get_parent_element(self):
- """Returns the parent element of this element
- :rtype: Element
+ def get_parent_element(self) -> 'Element':
+ """Returns the parent element of this element.
"""
return self.__parent
- def set_parent_element(self, element):
- """Adds a parent element to this element
+ def set_parent_element(self, element: 'Element'):
+ """Adds a parent element to this element.
There's usually no need to call this method manually,
`add_child_element()` calls it automatically.
-
- :type element: Element
"""
self.__parent = element
@deprecated
- def get_individual(self):
- """Returns this element and all of its sub-elements represented as a GEDCOM string
+ def get_individual(self) -> str:
+ """Returns this element and all of its sub-elements represented as a GEDCOM string.
::deprecated:: As of version 1.0.0 use `to_gedcom_string()` method instead
- :rtype: str
"""
return self.to_gedcom_string(True)
- def to_gedcom_string(self, recursive=False):
- """Formats this element and optionally all of its sub-elements into a GEDCOM string
- :type recursive: bool
- :rtype: str
+ def to_gedcom_string(self, recursive: bool = False) -> str:
+ """Formats this element and optionally all of its sub-elements into a GEDCOM string.
"""
result = str(self.get_level())
@@ -287,7 +289,7 @@ def to_gedcom_string(self, recursive=False):
return result
- def __str__(self):
+ def __str__(self) -> str:
""":rtype: str"""
if version_info[0] >= 3:
return self.to_gedcom_string()
diff --git a/gedcom/element/family.py b/gedcom/element/family.py
index c91b5a9..ff735bb 100644
--- a/gedcom/element/family.py
+++ b/gedcom/element/family.py
@@ -2,6 +2,7 @@
# Python GEDCOM Parser
#
+# Copyright (C) 2020 Christopher Horn (cdhorn at embarqmail dot com)
# Copyright (C) 2018 Damon Brodie (damon.brodie at gmail.com)
# Copyright (C) 2018-2019 Nicklas Reincke (contact at reynke.com)
# Copyright (C) 2016 Andreas Oberritter
@@ -25,17 +26,104 @@
#
# Further information about the license: http://www.gnu.org/licenses/gpl-2.0.html
-"""GEDCOM element consisting of tag `gedcom.tags.GEDCOM_TAG_FAMILY`"""
+"""
+GEDCOM element for a `FAM_RECORD` family record identified by the
+`gedcom.tags.GEDCOM_TAG_FAMILY` tag.
+"""
+import gedcom.tags as tags
from gedcom.element.element import Element
-import gedcom.tags
+from gedcom.subparsers.family_event_structure import family_event_structure
+from gedcom.subparsers.change_date import change_date
+from gedcom.subparsers.lds_spouse_sealing import lds_spouse_sealing
+from gedcom.subparsers.note_structure import note_structure
+from gedcom.subparsers.source_citation import source_citation
+from gedcom.subparsers.multimedia_link import multimedia_link
+from gedcom.subparsers.user_reference_number import user_reference_number
-
-class NotAnActualFamilyError(Exception):
- pass
+FAMILY_SINGLE_TAGS = {
+ tags.GEDCOM_TAG_WIFE: 'key_to_wife',
+ tags.GEDCOM_TAG_HUSBAND: 'key_to_husband',
+ tags.GEDCOM_TAG_CHILDREN_COUNT: 'number_of_children',
+ tags.GEDCOM_TAG_RESTRICTION: 'restriction',
+ tags.GEDCOM_TAG_REC_ID_NUMBER: 'record_id'
+}
class FamilyElement(Element):
+ """Element associated with a `FAM_RECORD`"""
+
+ def get_tag(self) -> str:
+ return tags.GEDCOM_TAG_FAMILY
+
+ def get_record(self) -> dict:
+ """Parse and return the full record in dictionary format.
+ """
+ record = {
+ 'key_to_family': self.get_pointer(),
+ 'restriction': '',
+ 'events': family_event_structure(self),
+ 'key_to_husband': '',
+ 'key_to_wife': '',
+ 'children': [],
+ 'number_of_children': '',
+ 'submitters': [],
+ 'references': [],
+ 'record_id': '',
+ 'change_date': {},
+ 'notes': [],
+ 'citations': [],
+ 'media': []
+ }
+ lds_events = lds_spouse_sealing(self)
+ if len(lds_events) > 0:
+ for event in lds_events:
+ record['events'].append(event)
+
+ for child in self.get_child_elements():
+ if child.get_tag() in FAMILY_SINGLE_TAGS:
+ record[FAMILY_SINGLE_TAGS[child.get_tag()]] = child.get_value()
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_CHILD:
+ entry = {
+ 'key_to_child': child.get_value(),
+ 'relationship_to_father': '',
+ 'relationship_to_mother': ''
+ }
+ for gchild in child.get_child_elements():
+ if gchild.get_tag() == tags.GEDCOM_PROGRAM_DEFINED_TAG_FREL:
+ entry['relationship_to_father'] = gchild.get_value()
+ continue
+
+ if gchild.get_tag() == tags.GEDCOM_PROGRAM_DEFINED_TAG_MREL:
+ entry['relationship_to_mother'] = gchild.get_value()
+
+ record['children'].append(entry)
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_NOTE:
+ record['notes'].append(note_structure(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_SOURCE:
+ record['citations'].append(source_citation(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_OBJECT:
+ record['media'].append(multimedia_link(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_REFERENCE:
+ record['references'].append(user_reference_number(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_CHANGE:
+ record['change_date'] = change_date(child)
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_SUBMITTER:
+ record['submitters'].append(child.get_value())
+ continue
- def get_tag(self):
- return gedcom.tags.GEDCOM_TAG_FAMILY
+ return record
diff --git a/gedcom/element/header.py b/gedcom/element/header.py
new file mode 100644
index 0000000..55399d9
--- /dev/null
+++ b/gedcom/element/header.py
@@ -0,0 +1,159 @@
+# -*- coding: utf-8 -*-
+
+# Python GEDCOM Parser
+#
+# Copyright (C) 2020 Christopher Horn (cdhorn at embarqmail dot com)
+# Copyright (C) 2018 Damon Brodie (damon.brodie at gmail.com)
+# Copyright (C) 2018-2019 Nicklas Reincke (contact at reynke.com)
+# Copyright (C) 2016 Andreas Oberritter
+# Copyright (C) 2012 Madeleine Price Ball
+# Copyright (C) 2005 Daniel Zappala (zappala at cs.byu.edu)
+# Copyright (C) 2005 Brigham Young University
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Further information about the license: http://www.gnu.org/licenses/gpl-2.0.html
+
+"""
+GEDCOM element for a `HEADER` header record identified by the
+`gedcom.tags.GEDCOM_TAG_HEADER` tag.
+"""
+
+import gedcom.tags as tags
+from gedcom.element.element import Element
+from gedcom.subparsers.address_structure import address_structure
+from gedcom.subparsers.note_structure import note_structure
+
+HEADER_TAGS = {
+ tags.GEDCOM_TAG_DESTINATION: 'destination',
+ tags.GEDCOM_TAG_SUBMITTER: 'key_to_submitter',
+ tags.GEDCOM_TAG_SUBMISSION: 'key_to_submission',
+ tags.GEDCOM_TAG_FILE: 'file',
+ tags.GEDCOM_TAG_COPYRIGHT: 'copyright',
+ tags.GEDCOM_TAG_LANGUAGE: 'language',
+ tags.GEDCOM_PROGRAM_DEFINED_TAG_HOME_PERSON: 'key_to_home_person'
+}
+
+
+class HeaderElement(Element):
+ """Element associated with a `HEADER`"""
+
+ def get_tag(self) -> str:
+ return tags.GEDCOM_TAG_HEADER
+
+ def get_record(self) -> dict:
+ """Parse and return the full record in dictionary format.
+ """
+ record = {
+ 'source': '',
+ 'product': {
+ 'version': '',
+ 'name': '',
+ 'corporation': '',
+ 'address': {}
+ },
+ 'data': {
+ 'source_data': '',
+ 'published': '',
+ 'copyright': ''
+ },
+ 'destination': '',
+ 'transmission_date': '',
+ 'transmission_time': '',
+ 'key_to_submitter': '',
+ 'key_to_submission': '',
+ 'file': '',
+ 'copyright': '',
+ 'gedcom': {
+ 'version': '',
+ 'format': '',
+ },
+ 'character_set': '',
+ 'character_set_version': '',
+ 'language': '',
+ 'place_hierarchy': '',
+ 'key_to_home_person': '',
+ 'notes': []
+ }
+ for child in self.get_child_elements():
+ if child.get_tag() == tags.GEDCOM_TAG_SOURCE:
+ record['source'] = child.get_value()
+ for gchild in child.get_child_elements():
+ if gchild.get_tag() == tags.GEDCOM_TAG_VERSION:
+ record['product']['version'] = gchild.get_value()
+ continue
+
+ if gchild.get_tag() == tags.GEDCOM_TAG_NAME:
+ record['product']['name'] = gchild.get_value()
+ continue
+
+ if gchild.get_tag() == tags.GEDCOM_TAG_CORPORATE:
+ record['product']['corporation'] = gchild.get_value()
+
+ for ggchild in gchild.get_child_elements():
+ if ggchild.get_tag() == tags.GEDCOM_TAG_ADDRESS:
+ record['product']['address'] = address_structure(gchild)
+ continue
+
+ if gchild.get_tag() == tags.GEDCOM_TAG_DATA:
+ record['data']['source_data'] = gchild.get_value()
+ for ggchild in gchild.get_child_elements():
+ if ggchild.get_tag() == tags.GEDCOM_TAG_DATE:
+ record['data']['published'] = ggchild.get_value()
+ continue
+
+ if ggchild.get_tag() == tags.GEDCOM_TAG_COPYRIGHT:
+ record['data']['copyright'] = ggchild.get_multi_line_value()
+ continue
+ continue
+
+ if child.get_tag() in HEADER_TAGS:
+ record[HEADER_TAGS[child.get_tag()]] = child.get_value()
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_DATE:
+ record['transmission_date'] = child.get_value()
+ for gchild in child.get_child_elements():
+ if gchild.get_tag() == tags.GEDCOM_TAG_TIME:
+ record['transmission_time'] = gchild.get_value()
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_GEDCOM:
+ for gchild in child.get_child_elements():
+ if gchild.get_tag() == tags.GEDCOM_TAG_VERSION:
+ record['gedcom']['version'] = gchild.get_value()
+ continue
+
+ if gchild.get_tag() == tags.GEDCOM_TAG_FORMAT:
+ record['gedcom']['format'] = gchild.get_value()
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_CHARACTER:
+ record['character_set'] = child.get_value()
+ for gchild in child.get_child_elements():
+ if gchild.get_tag() == tags.GEDCOM_TAG_VERSION:
+ record['character_set_version'] = gchild.get_value()
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_PLACE:
+ for gchild in child.get_child_elements():
+ if gchild.get_tag() == tags.GEDCOM_TAG_FORMAT:
+ record['place_hierarchy'] = gchild.get_value()
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_NOTE:
+ record['notes'].append(note_structure(child))
+
+ return record
diff --git a/gedcom/element/individual.py b/gedcom/element/individual.py
index da61d08..f2af5d4 100644
--- a/gedcom/element/individual.py
+++ b/gedcom/element/individual.py
@@ -2,6 +2,7 @@
# Python GEDCOM Parser
#
+# Copyright (C) 2020 Christopher Horn (cdhorn at embarqmail dot com)
# Copyright (C) 2018 Damon Brodie (damon.brodie at gmail.com)
# Copyright (C) 2018-2019 Nicklas Reincke (contact at reynke.com)
# Copyright (C) 2016 Andreas Oberritter
@@ -25,71 +26,179 @@
#
# Further information about the license: http://www.gnu.org/licenses/gpl-2.0.html
-"""GEDCOM element consisting of tag `gedcom.tags.GEDCOM_TAG_INDIVIDUAL`"""
+"""
+GEDCOM element for a `INDIVIDUAL_RECORD` individual record identified by the
+`gedcom.tags.GEDCOM_TAG_INDIVIDUAL` tag.
+"""
+from typing import Tuple, List
import re as regex
+
+import gedcom.tags as tags
from gedcom.element.element import Element
+from gedcom.subparsers.personal_name_structure import personal_name_structure
+from gedcom.subparsers.individual_event_structure import individual_event_structure
+from gedcom.subparsers.individual_attribute_structure import individual_attribute_structure
+from gedcom.subparsers.lds_individual_ordinance import lds_individual_ordinance
+from gedcom.subparsers.child_to_family_link import child_to_family_link
+from gedcom.subparsers.spouse_to_family_link import spouse_to_family_link
+from gedcom.subparsers.association_structure import association_structure
+from gedcom.subparsers.user_reference_number import user_reference_number
+from gedcom.subparsers.change_date import change_date
+from gedcom.subparsers.note_structure import note_structure
+from gedcom.subparsers.source_citation import source_citation
+from gedcom.subparsers.multimedia_link import multimedia_link
from gedcom.helpers import deprecated
-import gedcom.tags
-
-class NotAnActualIndividualError(Exception):
- pass
+INDIVIDUAL_SINGLE_TAGS = {
+ tags.GEDCOM_TAG_RESTRICTION: 'restriction',
+ tags.GEDCOM_TAG_SEX: 'sex',
+ tags.GEDCOM_TAG_REC_ID_NUMBER: 'record_id',
+ tags.GEDCOM_TAG_REC_FILE_NUMBER: 'permanent_file_number',
+ tags.GEDCOM_TAG_AFN: 'ancestral_file_number'
+}
class IndividualElement(Element):
+ """Element associated with an `INDIVIDUAL_RECORD`"""
- def get_tag(self):
- return gedcom.tags.GEDCOM_TAG_INDIVIDUAL
+ def get_tag(self) -> str:
+ return tags.GEDCOM_TAG_INDIVIDUAL
- def is_deceased(self):
- """Checks if this individual is deceased
- :rtype: bool
+ def get_record(self) -> dict:
+ """Parse and return the full record in dictionary format.
"""
+ record = {
+ 'key_to_individual': self.get_pointer(),
+ 'restriction': '',
+ 'names': [],
+ 'sex': 'U',
+ 'events': individual_event_structure(self),
+ 'attributes': individual_attribute_structure(self),
+ 'child_to_family': [],
+ 'spouse_to_family': [],
+ 'submitters': [],
+ 'associates': [],
+ 'aliases': [],
+ 'ancestors_interest': [],
+ 'descendants_interest': [],
+ 'permanent_file_number': '',
+ 'ancestral_file_number': '',
+ 'references': [],
+ 'record_id': '',
+ 'change_date': {},
+ 'notes': [],
+ 'citations': [],
+ 'media': []
+ }
+ lds_events = lds_individual_ordinance(self)
+ if len(lds_events) > 0:
+ for event in lds_events:
+ record['events'].append(event)
+
for child in self.get_child_elements():
- if child.get_tag() == gedcom.tags.GEDCOM_TAG_DEATH:
+ if child.get_tag() in INDIVIDUAL_SINGLE_TAGS:
+ record[INDIVIDUAL_SINGLE_TAGS[child.get_tag()]] = child.get_value()
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_NAME:
+ record['names'].append(personal_name_structure(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_FAMILY_CHILD:
+ record['child_to_family'].append(child_to_family_link(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_FAMILY_SPOUSE:
+ record['spouse_to_family'].append(spouse_to_family_link(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_NOTE:
+ record['notes'].append(note_structure(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_SOURCE:
+ record['citations'].append(source_citation(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_MEDIA:
+ record['media'].append(multimedia_link(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_SUBMITTER:
+ record['submitters'].append(child.get_value())
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_ASSOCIATES:
+ record['associates'].append(association_structure(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_ALIAS:
+ record['aliases'].append(child.get_value())
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_ANCES_INTEREST:
+ record['ancestors_interest'].append(child.get_value())
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_DESCENDANTS_INT:
+ record['descendants_interest'].append(child.get_value())
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_REFERENCE:
+ record['references'].append(user_reference_number(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_CHANGE:
+ record['changed'] = change_date(child)
+
+ return record
+
+ def is_deceased(self) -> bool:
+ """Checks if this individual is deceased.
+ """
+ for child in self.get_child_elements():
+ if child.get_tag() == tags.GEDCOM_TAG_DEATH:
return True
return False
- def is_child(self):
- """Checks if this element is a child of a family
- :rtype: bool
+ def is_child(self) -> bool:
+ """Checks if this element is a child of a family.
"""
found_child = False
for child in self.get_child_elements():
- if child.get_tag() == gedcom.tags.GEDCOM_TAG_FAMILY_CHILD:
+ if child.get_tag() == tags.GEDCOM_TAG_FAMILY_CHILD:
found_child = True
return found_child
- def is_private(self):
- """Checks if this individual is marked private
- :rtype: bool
+ def is_private(self) -> bool:
+ """Checks if this individual is marked private.
"""
for child in self.get_child_elements():
- if child.get_tag() == gedcom.tags.GEDCOM_TAG_PRIVATE:
+ if child.get_tag() == tags.GEDCOM_TAG_PRIVATE:
private = child.get_value()
if private == 'Y':
return True
return False
- def get_name(self):
+ def get_name(self) -> Tuple[str, str]:
"""Returns an individual's names as a tuple: (`str` given_name, `str` surname)
- :rtype: tuple
"""
given_name = ""
surname = ""
- # Return the first gedcom.tags.GEDCOM_TAG_NAME that is found.
- # Alternatively as soon as we have both the gedcom.tags.GEDCOM_TAG_GIVEN_NAME and _SURNAME return those.
+ # Return the first tags.GEDCOM_TAG_NAME that is found.
+ # Alternatively as soon as we have both the tags.GEDCOM_TAG_GIVEN_NAME
+ # and _SURNAME return those.
found_given_name = False
found_surname_name = False
for child in self.get_child_elements():
- if child.get_tag() == gedcom.tags.GEDCOM_TAG_NAME:
+ if child.get_tag() == tags.GEDCOM_TAG_NAME:
# Some GEDCOM files don't use child tags but instead
# place the name in the value of the NAME tag.
if child.get_value() != "":
@@ -102,14 +211,14 @@ def get_name(self):
return given_name, surname
- for childOfChild in child.get_child_elements():
+ for gchild in child.get_child_elements():
- if childOfChild.get_tag() == gedcom.tags.GEDCOM_TAG_GIVEN_NAME:
- given_name = childOfChild.get_value()
+ if gchild.get_tag() == tags.GEDCOM_TAG_GIVEN_NAME:
+ given_name = gchild.get_value()
found_given_name = True
- if childOfChild.get_tag() == gedcom.tags.GEDCOM_TAG_SURNAME:
- surname = childOfChild.get_value()
+ if gchild.get_tag() == tags.GEDCOM_TAG_SURNAME:
+ surname = gchild.get_value()
found_surname_name = True
if found_given_name and found_surname_name:
@@ -118,80 +227,74 @@ def get_name(self):
# If we reach here we are probably returning empty strings
return given_name, surname
- def get_all_names(self):
- return [a.get_value() for a in self.get_child_elements() if a.get_tag() == gedcom.tags.GEDCOM_TAG_NAME]
+ def get_all_names(self) -> List[str]:
+ """Return all names."""
+ return [a.get_value() for a in self.get_child_elements()
+ if a.get_tag() == tags.GEDCOM_TAG_NAME]
- def surname_match(self, surname_to_match):
- """Matches a string with the surname of an individual
- :type surname_to_match: str
- :rtype: bool
+ def surname_match(self, surname_to_match: str) -> bool:
+ """Matches a string with the surname of an individual.
"""
(given_name, surname) = self.get_name()
return regex.search(surname_to_match, surname, regex.IGNORECASE)
@deprecated
- def given_match(self, name):
- """Matches a string with the given name of an individual
+ def given_match(self, name: str) -> bool:
+ """Matches a string with the given name of an individual.
::deprecated:: As of version 1.0.0 use `given_name_match()` method instead
- :type name: str
- :rtype: bool
"""
return self.given_name_match(name)
- def given_name_match(self, given_name_to_match):
- """Matches a string with the given name of an individual
- :type given_name_to_match: str
- :rtype: bool
+ def given_name_match(self, given_name_to_match: str) -> bool:
+ """Matches a string with the given name of an individual.
"""
(given_name, surname) = self.get_name()
return regex.search(given_name_to_match, given_name, regex.IGNORECASE)
- def get_gender(self):
- """Returns the gender of a person in string format
- :rtype: str
+ def get_gender(self) -> str:
+ """Returns the gender of a person in string format.
"""
gender = ""
for child in self.get_child_elements():
- if child.get_tag() == gedcom.tags.GEDCOM_TAG_SEX:
+ if child.get_tag() == tags.GEDCOM_TAG_SEX:
gender = child.get_value()
return gender
- def get_birth_data(self):
- """Returns the birth data of a person formatted as a tuple: (`str` date, `str` place, `list` sources)
- :rtype: tuple
+ def get_birth_data(self) -> Tuple[str, str, List[str]]:
+ """Returns the birth data of a person formatted as a tuple:
+ (`str` date, `str` place, `list` sources)
"""
date = ""
place = ""
sources = []
for child in self.get_child_elements():
- if child.get_tag() == gedcom.tags.GEDCOM_TAG_BIRTH:
- for childOfChild in child.get_child_elements():
+ if child.get_tag() == tags.GEDCOM_TAG_BIRTH:
+ for gchild in child.get_child_elements():
- if childOfChild.get_tag() == gedcom.tags.GEDCOM_TAG_DATE:
- date = childOfChild.get_value()
+ if gchild.get_tag() == tags.GEDCOM_TAG_DATE:
+ date = gchild.get_value()
- if childOfChild.get_tag() == gedcom.tags.GEDCOM_TAG_PLACE:
- place = childOfChild.get_value()
+ if gchild.get_tag() == tags.GEDCOM_TAG_PLACE:
+ place = gchild.get_value()
- if childOfChild.get_tag() == gedcom.tags.GEDCOM_TAG_SOURCE:
- sources.append(childOfChild.get_value())
+ if gchild.get_tag() == tags.GEDCOM_TAG_SOURCE:
+ sources.append(gchild.get_value())
return date, place, sources
- def get_birth_year(self):
- """Returns the birth year of a person in integer format
- :rtype: int
+ def get_birth_year(self) -> int:
+ """Returns the birth year of a person in integer format.
"""
date = ""
for child in self.get_child_elements():
- if child.get_tag() == gedcom.tags.GEDCOM_TAG_BIRTH:
- for childOfChild in child.get_child_elements():
- if childOfChild.get_tag() == gedcom.tags.GEDCOM_TAG_DATE:
- date_split = childOfChild.get_value().split()
+ if child.get_tag() == tags.GEDCOM_TAG_BIRTH:
+ for gchild in child.get_child_elements():
+ if gchild.get_tag() == tags.GEDCOM_TAG_DATE:
+ date_split = gchild.get_value().split()
date = date_split[len(date_split) - 1]
if date == "":
@@ -201,37 +304,36 @@ def get_birth_year(self):
except ValueError:
return -1
- def get_death_data(self):
- """Returns the death data of a person formatted as a tuple: (`str` date, `str` place, `list` sources)
- :rtype: tuple
+ def get_death_data(self) -> Tuple[str, str, List[str]]:
+ """Returns the death data of a person formatted as a tuple:
+ (`str` date, `str` place, `list` sources)
"""
date = ""
place = ""
sources = []
for child in self.get_child_elements():
- if child.get_tag() == gedcom.tags.GEDCOM_TAG_DEATH:
- for childOfChild in child.get_child_elements():
- if childOfChild.get_tag() == gedcom.tags.GEDCOM_TAG_DATE:
- date = childOfChild.get_value()
- if childOfChild.get_tag() == gedcom.tags.GEDCOM_TAG_PLACE:
- place = childOfChild.get_value()
- if childOfChild.get_tag() == gedcom.tags.GEDCOM_TAG_SOURCE:
- sources.append(childOfChild.get_value())
+ if child.get_tag() == tags.GEDCOM_TAG_DEATH:
+ for gchild in child.get_child_elements():
+ if gchild.get_tag() == tags.GEDCOM_TAG_DATE:
+ date = gchild.get_value()
+ if gchild.get_tag() == tags.GEDCOM_TAG_PLACE:
+ place = gchild.get_value()
+ if gchild.get_tag() == tags.GEDCOM_TAG_SOURCE:
+ sources.append(gchild.get_value())
return date, place, sources
- def get_death_year(self):
- """Returns the death year of a person in integer format
- :rtype: int
+ def get_death_year(self) -> int:
+ """Returns the death year of a person in integer format.
"""
date = ""
for child in self.get_child_elements():
- if child.get_tag() == gedcom.tags.GEDCOM_TAG_DEATH:
- for childOfChild in child.get_child_elements():
- if childOfChild.get_tag() == gedcom.tags.GEDCOM_TAG_DATE:
- date_split = childOfChild.get_value().split()
+ if child.get_tag() == tags.GEDCOM_TAG_DEATH:
+ for gchild in child.get_child_elements():
+ if gchild.get_tag() == tags.GEDCOM_TAG_DATE:
+ date_split = gchild.get_value().split()
date = date_split[len(date_split) - 1]
if date == "":
@@ -242,110 +344,103 @@ def get_death_year(self):
return -1
@deprecated
- def get_burial(self):
- """Returns the burial data of a person formatted as a tuple: (`str` date, `str´ place, `list` sources)
+ def get_burial(self) -> Tuple[str, str, List[str]]:
+ """Returns the burial data of a person formatted as a tuple:
+ (`str` date, `str´ place, `list` sources)
::deprecated:: As of version 1.0.0 use `get_burial_data()` method instead
- :rtype: tuple
"""
self.get_burial_data()
- def get_burial_data(self):
- """Returns the burial data of a person formatted as a tuple: (`str` date, `str´ place, `list` sources)
- :rtype: tuple
+ def get_burial_data(self) -> Tuple[str, str, List[str]]:
+ """Returns the burial data of a person formatted as a tuple:
+ (`str` date, `str´ place, `list` sources)
"""
date = ""
place = ""
sources = []
for child in self.get_child_elements():
- if child.get_tag() == gedcom.tags.GEDCOM_TAG_BURIAL:
- for childOfChild in child.get_child_elements():
+ if child.get_tag() == tags.GEDCOM_TAG_BURIAL:
+ for gchild in child.get_child_elements():
- if childOfChild.get_tag() == gedcom.tags.GEDCOM_TAG_DATE:
- date = childOfChild.get_value()
+ if gchild.get_tag() == tags.GEDCOM_TAG_DATE:
+ date = gchild.get_value()
- if childOfChild.get_tag() == gedcom.tags.GEDCOM_TAG_PLACE:
- place = childOfChild.get_value()
+ if gchild.get_tag() == tags.GEDCOM_TAG_PLACE:
+ place = gchild.get_value()
- if childOfChild.get_tag() == gedcom.tags.GEDCOM_TAG_SOURCE:
- sources.append(childOfChild.get_value())
+ if gchild.get_tag() == tags.GEDCOM_TAG_SOURCE:
+ sources.append(gchild.get_value())
return date, place, sources
@deprecated
- def get_census(self):
- """Returns a list of censuses of an individual formatted as tuples: (`str` date, `str´ place, `list` sources)
+ def get_census(self) -> List[Tuple[str, str, List[str]]]:
+ """Returns a list of censuses of an individual formatted as tuples:
+ (`str` date, `str´ place, `list` sources)
::deprecated:: As of version 1.0.0 use `get_census_data()` method instead
- :rtype: list of tuple
"""
self.get_census_data()
- def get_census_data(self):
- """Returns a list of censuses of an individual formatted as tuples: (`str` date, `str´ place, `list` sources)
- :rtype: list of tuple
+ def get_census_data(self) -> List[Tuple[str, str, List[str]]]:
+ """Returns a list of censuses of an individual formatted as tuples:
+ (`str` date, `str´ place, `list` sources)
"""
census = []
for child in self.get_child_elements():
- if child.get_tag() == gedcom.tags.GEDCOM_TAG_CENSUS:
+ if child.get_tag() == tags.GEDCOM_TAG_CENSUS:
date = ''
place = ''
sources = []
- for childOfChild in child.get_child_elements():
+ for gchild in child.get_child_elements():
- if childOfChild.get_tag() == gedcom.tags.GEDCOM_TAG_DATE:
- date = childOfChild.get_value()
+ if gchild.get_tag() == tags.GEDCOM_TAG_DATE:
+ date = gchild.get_value()
- if childOfChild.get_tag() == gedcom.tags.GEDCOM_TAG_PLACE:
- place = childOfChild.get_value()
+ if gchild.get_tag() == tags.GEDCOM_TAG_PLACE:
+ place = gchild.get_value()
- if childOfChild.get_tag() == gedcom.tags.GEDCOM_TAG_SOURCE:
- sources.append(childOfChild.get_value())
+ if gchild.get_tag() == tags.GEDCOM_TAG_SOURCE:
+ sources.append(gchild.get_value())
census.append((date, place, sources))
return census
- def get_last_change_date(self):
- """Returns the date of when the person data was last changed formatted as a string
- :rtype: str
+ def get_last_change_date(self) -> str:
+ """Returns the date of when the person data was last changed formatted as a string.
"""
date = ""
for child in self.get_child_elements():
- if child.get_tag() == gedcom.tags.GEDCOM_TAG_CHANGE:
- for childOfChild in child.get_child_elements():
- if childOfChild.get_tag() == gedcom.tags.GEDCOM_TAG_DATE:
- date = childOfChild.get_value()
+ if child.get_tag() == tags.GEDCOM_TAG_CHANGE:
+ for gchild in child.get_child_elements():
+ if gchild.get_tag() == tags.GEDCOM_TAG_DATE:
+ date = gchild.get_value()
return date
- def get_occupation(self):
- """Returns the occupation of a person
- :rtype: str
+ def get_occupation(self) -> str:
+ """Returns the occupation of a person.
"""
occupation = ""
for child in self.get_child_elements():
- if child.get_tag() == gedcom.tags.GEDCOM_TAG_OCCUPATION:
+ if child.get_tag() == tags.GEDCOM_TAG_OCCUPATION:
occupation = child.get_value()
return occupation
- def birth_year_match(self, year):
- """Returns `True` if the given year matches the birth year of this person
- :type year: int
- :rtype: bool
+ def birth_year_match(self, year: int) -> bool:
+ """Returns `True` if the given year matches the birth year of this person.
"""
return self.get_birth_year() == year
- def birth_range_match(self, from_year, to_year):
- """Checks if the birth year of a person lies within the given range
- :type from_year: int
- :type to_year: int
- :rtype: bool
+ def birth_range_match(self, from_year: int, to_year: int) -> bool:
+ """Checks if the birth year of a person lies within the given range.
"""
birth_year = self.get_birth_year()
@@ -354,18 +449,13 @@ def birth_range_match(self, from_year, to_year):
return False
- def death_year_match(self, year):
- """Returns `True` if the given year matches the death year of this person
- :type year: int
- :rtype: bool
+ def death_year_match(self, year: int) -> bool:
+ """Returns `True` if the given year matches the death year of this person.
"""
return self.get_death_year() == year
- def death_range_match(self, from_year, to_year):
- """Checks if the death year of a person lies within the given range
- :type from_year: int
- :type to_year: int
- :rtype: bool
+ def death_range_match(self, from_year: int, to_year: int) -> bool:
+ """Checks if the death year of a person lies within the given range.
"""
death_year = self.get_death_year()
@@ -374,8 +464,8 @@ def death_range_match(self, from_year, to_year):
return False
- def criteria_match(self, criteria):
- """Checks if this individual matches all of the given criteria
+ def criteria_match(self, criteria: str) -> bool:
+ """Checks if this individual matches all of the given criteria.
`criteria` is a colon-separated list, where each item in the
list has the form [name]=[value]. The following criteria are supported:
@@ -389,9 +479,6 @@ def criteria_match(self, criteria):
birth_range=[from_year-to_year]
Match a person whose birth year is in the range of years from
[from_year] to [to_year], including both [from_year] and [to_year].
-
- :type criteria: str
- :rtype: bool
"""
# Check if criteria is a valid criteria and can be split by `:` and `=` characters
diff --git a/gedcom/element/note.py b/gedcom/element/note.py
new file mode 100644
index 0000000..2035f54
--- /dev/null
+++ b/gedcom/element/note.py
@@ -0,0 +1,74 @@
+# -*- coding: utf-8 -*-
+
+# Python GEDCOM Parser
+#
+# Copyright (C) 2020 Christopher Horn (cdhorn at embarqmail dot com)
+# Copyright (C) 2018 Damon Brodie (damon.brodie at gmail.com)
+# Copyright (C) 2018-2019 Nicklas Reincke (contact at reynke.com)
+# Copyright (C) 2016 Andreas Oberritter
+# Copyright (C) 2012 Madeleine Price Ball
+# Copyright (C) 2005 Daniel Zappala (zappala at cs.byu.edu)
+# Copyright (C) 2005 Brigham Young University
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Further information about the license: http://www.gnu.org/licenses/gpl-2.0.html
+
+"""
+GEDCOM element for a `NOTE_RECORD` note record identified by the
+`gedcom.tags.GEDCOM_TAG_NOTE` tag.
+"""
+
+import gedcom.tags as tags
+from gedcom.element.element import Element
+from gedcom.subparsers.source_citation import source_citation
+from gedcom.subparsers.change_date import change_date
+from gedcom.subparsers.user_reference_number import user_reference_number
+
+
+class NoteElement(Element):
+ """Element associated with a `NOTE_RECORD`"""
+
+ def get_tag(self) -> str:
+ return tags.GEDCOM_TAG_NOTE
+
+ def get_record(self) -> dict:
+ """Parse and return the full record in dictionary format.
+ """
+ record = {
+ 'key_to_note': self.get_pointer(),
+ 'note': self.get_multi_line_value(),
+ 'references': [],
+ 'record_id': '',
+ 'citations': [],
+ 'change_date': {}
+ }
+ for child in self.get_child_elements():
+ if child.get_tag() == tags.GEDCOM_TAG_REFERENCE:
+ record['references'].append(user_reference_number(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_REC_ID_NUMBER:
+ record['record_id'] = child.get_value()
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_SOURCE:
+ record['citations'].append(source_citation(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_CHANGE:
+ record['change_date'] = change_date(child)
+
+ return record
diff --git a/gedcom/element/object.py b/gedcom/element/object.py
index 0090e2f..5942545 100644
--- a/gedcom/element/object.py
+++ b/gedcom/element/object.py
@@ -2,6 +2,7 @@
# Python GEDCOM Parser
#
+# Copyright (C) 2020 Christopher Horn (cdhorn at embarqmail dot com)
# Copyright (C) 2018 Damon Brodie (damon.brodie at gmail.com)
# Copyright (C) 2018-2019 Nicklas Reincke (contact at reynke.com)
# Copyright (C) 2016 Andreas Oberritter
@@ -25,20 +26,83 @@
#
# Further information about the license: http://www.gnu.org/licenses/gpl-2.0.html
-"""GEDCOM element consisting of tag `gedcom.tags.GEDCOM_TAG_OBJECT`"""
+"""
+GEDCOM element for a `MULTIMEDIA_RECORD` media record identified by the
+`gedcom.tags.GEDCOM_TAG_OBJECT` tag.
+"""
+import gedcom.tags as tags
from gedcom.element.element import Element
-import gedcom.tags
-
-
-class NotAnActualObjectError(Exception):
- pass
+from gedcom.subparsers.note_structure import note_structure
+from gedcom.subparsers.source_citation import source_citation
+from gedcom.subparsers.change_date import change_date
+from gedcom.subparsers.user_reference_number import user_reference_number
class ObjectElement(Element):
+ """Element associated with a `MULTIMEDIA_RECORD`"""
- def is_object(self):
- """Checks if this element is an actual object
- :rtype: bool
+ def get_tag(self) -> str:
+ return tags.GEDCOM_TAG_OBJECT
+
+ def get_record(self) -> dict:
+ """Parse and return the full record in dictionary format.
"""
- return self.get_tag() == gedcom.tags.GEDCOM_TAG_OBJECT
+ record = {
+ 'key_to_object': self.get_pointer(),
+ 'file': '',
+ 'format': '',
+ 'type': '',
+ 'title': '',
+ 'references': [],
+ 'record_id': '',
+ 'citations': [],
+ 'notes': [],
+ 'change_date': {}
+ }
+ for child in self.get_child_elements():
+ if child.get_tag() == tags.GEDCOM_TAG_FILE:
+ record['file'] = child.get_value()
+
+ for gchild in child.get_child_elements():
+ if gchild.get_tag() == tags.GEDCOM_TAG_FORMAT:
+ record['format'] = gchild.get_value()
+
+ for ggchild in gchild.get_child_elements():
+ if ggchild.get_tag() == tags.GEDCOM_TAG_TYPE:
+ record['type'] = ggchild.get_value()
+ continue
+
+ if gchild.get_tag() == tags.GEDCOM_TAG_TITLE:
+ record['title'] = gchild.get_value()
+ continue
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_FORMAT:
+ record['format'] = child.get_value()
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_TYPE:
+ record['type'] = child.get_value()
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_NOTE:
+ record['notes'].append(note_structure(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_SOURCE:
+ record['citations'].append(source_citation(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_REFERENCE:
+ record['references'].append(user_reference_number(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_REC_ID_NUMBER:
+ record['record_id'] = child.get_value()
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_CHANGE:
+ record['change_date'] = change_date(child)
+
+ return record
diff --git a/gedcom/element/repository.py b/gedcom/element/repository.py
new file mode 100644
index 0000000..f0dc469
--- /dev/null
+++ b/gedcom/element/repository.py
@@ -0,0 +1,84 @@
+# -*- coding: utf-8 -*-
+
+# Python GEDCOM Parser
+#
+# Copyright (C) 2020 Christopher Horn (cdhorn at embarqmail dot com)
+# Copyright (C) 2018 Damon Brodie (damon.brodie at gmail.com)
+# Copyright (C) 2018-2019 Nicklas Reincke (contact at reynke.com)
+# Copyright (C) 2016 Andreas Oberritter
+# Copyright (C) 2012 Madeleine Price Ball
+# Copyright (C) 2005 Daniel Zappala (zappala at cs.byu.edu)
+# Copyright (C) 2005 Brigham Young University
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Further information about the license: http://www.gnu.org/licenses/gpl-2.0.html
+
+"""
+GEDCOM element for a `REPOSITORY_RECORD` repository record identified by the
+`gedcom.tags.GEDCOM_TAG_REPOSITORY` tag.
+"""
+
+import gedcom.tags as tags
+from gedcom.element.element import Element
+from gedcom.subparsers.address_structure import address_structure
+from gedcom.subparsers.note_structure import note_structure
+from gedcom.subparsers.change_date import change_date
+from gedcom.subparsers.user_reference_number import user_reference_number
+
+
+class RepositoryElement(Element):
+ """Element associated with a `REPOSITORY_RECORD`"""
+
+ def get_tag(self) -> str:
+ return tags.GEDCOM_TAG_REPOSITORY
+
+ def get_record(self) -> dict:
+ """Parse and return the full record in dictionary format.
+ """
+ record = {
+ 'key_to_repository': self.get_pointer(),
+ 'name': '',
+ 'address': {},
+ 'references': [],
+ 'record_id': '',
+ 'change_date': {},
+ 'notes': []
+ }
+ for child in self.get_child_elements():
+ if child.get_tag() == tags.GEDCOM_TAG_NAME:
+ record['name'] = child.get_value()
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_ADDRESS:
+ record['address'] = address_structure(self)
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_NOTE:
+ record['notes'].append(note_structure(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_REFERENCE:
+ record['references'].append(user_reference_number(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_REC_ID_NUMBER:
+ record['record_id'] = child.get_value()
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_CHANGE:
+ record['change_date'] = change_date(child)
+
+ return record
diff --git a/gedcom/element/root.py b/gedcom/element/root.py
index 826c378..6ad719a 100644
--- a/gedcom/element/root.py
+++ b/gedcom/element/root.py
@@ -31,7 +31,8 @@
class RootElement(Element):
- """Virtual GEDCOM root element containing all logical records as children"""
+ """Virtual GEDCOM root element containing all logical records as children."""
- def __init__(self, level=-1, pointer="", tag="ROOT", value="", crlf="\n", multi_line=True):
+ def __init__(self, level: int = -1, pointer: str = "", tag: str = "ROOT", value: str = "",
+ crlf: str = "\n", multi_line: bool = True):
super(RootElement, self).__init__(level, pointer, tag, value, crlf, multi_line)
diff --git a/gedcom/element/source.py b/gedcom/element/source.py
new file mode 100644
index 0000000..e73b52c
--- /dev/null
+++ b/gedcom/element/source.py
@@ -0,0 +1,137 @@
+# -*- coding: utf-8 -*-
+
+# Python GEDCOM Parser
+#
+# Copyright (C) 2020 Christopher Horn (cdhorn at embarqmail dot com)
+# Copyright (C) 2018 Damon Brodie (damon.brodie at gmail.com)
+# Copyright (C) 2018-2019 Nicklas Reincke (contact at reynke.com)
+# Copyright (C) 2016 Andreas Oberritter
+# Copyright (C) 2012 Madeleine Price Ball
+# Copyright (C) 2005 Daniel Zappala (zappala at cs.byu.edu)
+# Copyright (C) 2005 Brigham Young University
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Further information about the license: http://www.gnu.org/licenses/gpl-2.0.html
+
+"""
+GEDCOM element for a `SOURCE_RECORD` source record identified by the
+`gedcom.tags.GEDCOM_TAG_SOURCE` tag.
+"""
+
+import gedcom.tags as tags
+from gedcom.element.element import Element
+from gedcom.subparsers.change_date import change_date
+from gedcom.subparsers.note_structure import note_structure
+from gedcom.subparsers.multimedia_link import multimedia_link
+from gedcom.subparsers.user_reference_number import user_reference_number
+from gedcom.subparsers.source_repository_citation import source_repository_citation
+
+SOURCE_PLURAL_TAGS = {
+ tags.GEDCOM_TAG_AUTHOR: 'author',
+ tags.GEDCOM_TAG_TITLE: 'title',
+ tags.GEDCOM_TAG_PUBLICATION: 'publication',
+ tags.GEDCOM_TAG_TEXT: 'text'
+}
+
+SOURCE_SINGLE_TAGS = {
+ tags.GEDCOM_TAG_ABBREVIATION: 'abbreviation',
+ tags.GEDCOM_TAG_REC_ID_NUMBER: 'record_id',
+ tags.GEDCOM_PROGRAM_DEFINED_TAG_APID: 'apid'
+}
+
+
+class SourceElement(Element):
+ """Element associated with a SOURCE_RECORD"""
+
+ def get_tag(self) -> str:
+ return tags.GEDCOM_TAG_SOURCE
+
+ def get_record(self) -> dict:
+ """Parse and return the full record in dictionary format.
+ """
+ record = {
+ 'key_to_source': self.get_pointer(),
+ 'data': {
+ 'events': '',
+ 'date': '',
+ 'place': '',
+ 'agency': '',
+ 'notes': []
+ },
+ 'author': '',
+ 'title': '',
+ 'abbreviation': '',
+ 'publication': '',
+ 'text': '',
+ 'repository': {},
+ 'references': [],
+ 'record_id': '',
+ 'change_date': {},
+ 'notes': [],
+ 'media': [],
+ 'apid': ''
+ }
+ for child in self.get_child_elements():
+ if child.get_tag() in SOURCE_PLURAL_TAGS:
+ record[SOURCE_PLURAL_TAGS[child.get_tag()]] = child.get_multi_line_value()
+ continue
+
+ if child.get_tag() in SOURCE_SINGLE_TAGS:
+ record[SOURCE_SINGLE_TAGS[child.get_tag()]] = child.get_value()
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_NOTE:
+ record['notes'].append(note_structure(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_OBJECT:
+ record['media'].append(multimedia_link(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_REPOSITORY:
+ record['repository'] = source_repository_citation(child)
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_DATA:
+ for gchild in child.get_child_elements():
+ if gchild.get_tag() == tags.GEDCOM_TAG_EVENT:
+ record['data']['events'] = gchild.get_value()
+ for ggchild in gchild.get_child_elements():
+ if ggchild.get_tag() == tags.GEDCOM_TAG_DATE:
+ record['data']['date'] = ggchild.get_value()
+ continue
+
+ if ggchild.get_tag() == tags.GEDCOM_TAG_PLACE:
+ record['data']['place'] = ggchild.get_value()
+ continue
+
+ if gchild.get_tag() == tags.GEDCOM_TAG_AGENCY:
+ record['data']['agency'] = gchild.get_value()
+ continue
+
+ if gchild.get_tag() == tags.GEDCOM_TAG_NOTE:
+ record['data']['notes'].append(note_structure(gchild))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_REFERENCE:
+ record['references'].append(user_reference_number(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_CHANGE:
+ record['change_date'] = change_date(child)
+ continue
+
+ return record
diff --git a/gedcom/element/submission.py b/gedcom/element/submission.py
new file mode 100644
index 0000000..7eb90d3
--- /dev/null
+++ b/gedcom/element/submission.py
@@ -0,0 +1,83 @@
+# -*- coding: utf-8 -*-
+
+# Python GEDCOM Parser
+#
+# Copyright (C) 2020 Christopher Horn (cdhorn at embarqmail dot com)
+# Copyright (C) 2018 Damon Brodie (damon.brodie at gmail.com)
+# Copyright (C) 2018-2019 Nicklas Reincke (contact at reynke.com)
+# Copyright (C) 2016 Andreas Oberritter
+# Copyright (C) 2012 Madeleine Price Ball
+# Copyright (C) 2005 Daniel Zappala (zappala at cs.byu.edu)
+# Copyright (C) 2005 Brigham Young University
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Further information about the license: http://www.gnu.org/licenses/gpl-2.0.html
+
+"""
+GEDCOM element for a `SUBMISSION_RECORD` submission record identified by the
+`gedcom.tags.GEDCOM_TAG_SUBMISSION` tag.
+"""
+
+import gedcom.tags as tags
+from gedcom.element.element import Element
+from gedcom.subparsers.note_structure import note_structure
+from gedcom.subparsers.change_date import change_date
+
+SUBMISSION_TAGS = {
+ tags.GEDCOM_TAG_SUBMITTER: 'key_to_submitter',
+ tags.GEDCOM_TAG_FAMILY_FILE: 'family_file',
+ tags.GEDCOM_TAG_TEMPLE: 'temple',
+ tags.GEDCOM_TAG_ANCESTORS: 'generations_of_ancestors',
+ tags.GEDCOM_TAG_DESCENDANTS: 'generations_of_decendants',
+ tags.GEDCOM_TAG_ORDINANCE: 'ordinance_process_flag',
+ tags.GEDCOM_TAG_REC_ID_NUMBER: 'record_id'
+}
+
+
+class SubmissionElement(Element):
+ """Element associated with a `SUBMISSION_RECORD`"""
+
+ def get_tag(self) -> str:
+ return tags.GEDCOM_TAG_SUBMISSION
+
+ def get_record(self) -> dict:
+ """Parse and return the record in dictionary format
+ """
+ record = {
+ 'key_to_submission': self.get_pointer(),
+ 'key_to_submitter': '',
+ 'family_file': '',
+ 'temple': '',
+ 'generations_of_ancestors': '',
+ 'generations_of_descendants': '',
+ 'ordinance_process_flag': '',
+ 'record_id': '',
+ 'notes': [],
+ 'change_date': {}
+ }
+ for child in self.get_child_elements():
+ if child.get_tag() in SUBMISSION_TAGS:
+ record[SUBMISSION_TAGS[child.get_tag()]] = child.get_value()
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_NOTE:
+ record['notes'].append(note_structure(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_CHANGE:
+ record['change_date'] = change_date(child)
+
+ return record
diff --git a/gedcom/element/submitter.py b/gedcom/element/submitter.py
new file mode 100644
index 0000000..8e48737
--- /dev/null
+++ b/gedcom/element/submitter.py
@@ -0,0 +1,94 @@
+# -*- coding: utf-8 -*-
+
+# Python GEDCOM Parser
+#
+# Copyright (C) 2020 Christopher Horn (cdhorn at embarqmail dot com)
+# Copyright (C) 2018 Damon Brodie (damon.brodie at gmail.com)
+# Copyright (C) 2018-2019 Nicklas Reincke (contact at reynke.com)
+# Copyright (C) 2016 Andreas Oberritter
+# Copyright (C) 2012 Madeleine Price Ball
+# Copyright (C) 2005 Daniel Zappala (zappala at cs.byu.edu)
+# Copyright (C) 2005 Brigham Young University
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Further information about the license: http://www.gnu.org/licenses/gpl-2.0.html
+
+"""
+GEDCOM element for a `SUBMITTER_RECORD` submitter record identified by the
+`gedcom.tags.GEDCOM_TAG_SUBMITTER` tag.
+"""
+
+import gedcom.tags as tags
+from gedcom.element.element import Element
+from gedcom.subparsers.address_structure import address_structure
+from gedcom.subparsers.note_structure import note_structure
+from gedcom.subparsers.change_date import change_date
+from gedcom.subparsers.multimedia_link import multimedia_link
+
+
+class SubmitterElement(Element):
+ """Element associated with a `SUBMITTER_RECORD`"""
+
+ def get_tag(self) -> str:
+ return tags.GEDCOM_TAG_SUBMITTER
+
+ def get_record(self) -> dict:
+ """Parse and return the record in dictionary format
+ """
+ record = {
+ 'key_to_submitter': self.get_pointer(),
+ 'name': '',
+ 'address': {},
+ 'media': [],
+ 'language': '',
+ 'registered_file_number': '',
+ 'record_id': '',
+ 'notes': [],
+ 'change_date': {}
+ }
+ for child in self.get_child_elements():
+ if child.get_tag() == tags.GEDCOM_TAG_NAME:
+ record['name'] = child.get_value()
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_ADDRESS:
+ record['address'] = address_structure(self)
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_NOTE:
+ record['notes'].append(note_structure(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_OBJECT:
+ record['media'].append(multimedia_link(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_LANGUAGE:
+ record['language'] = child.get_value()
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_REC_FILE_NUMBER:
+ record['registered_file_number'] = child.get_value()
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_REC_ID_NUMBER:
+ record['record_id'] = child.get_value()
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_CHANGE:
+ record['change_date'] = change_date(child)
+
+ return record
diff --git a/gedcom/errors.py b/gedcom/errors.py
new file mode 100644
index 0000000..f8885f2
--- /dev/null
+++ b/gedcom/errors.py
@@ -0,0 +1,100 @@
+# -*- coding: utf-8 -*-
+
+# Python GEDCOM Parser
+#
+# Copyright (C) 2020 Christopher Horn (cdhorn at embarqmail dot com)
+# Copyright (C) 2018 Damon Brodie (damon.brodie at gmail.com)
+# Copyright (C) 2018-2019 Nicklas Reincke (contact at reynke.com)
+# Copyright (C) 2016 Andreas Oberritter
+# Copyright (C) 2012 Madeleine Price Ball
+# Copyright (C) 2005 Daniel Zappala (zappala at cs.byu.edu)
+# Copyright (C) 2005 Brigham Young University
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Further information about the license: http://www.gnu.org/licenses/gpl-2.0.html
+
+"""
+Module containing the exception handling classes.
+"""
+
+
+class GedcomFormatViolationError(Exception):
+ """Raised when the document format does not appear to conform
+ to the GEDCOM standard and strict parsing required.
+ """
+
+
+class GedcomStructureViolationError(Exception):
+ """Raised when the structure of a record does not conform to
+ the GEDCOM standard.
+ """
+
+
+class GedcomCharacterSetUnsupportedError(Exception):
+ """Raised when a GEDCOM appears to contain a character set
+ the standard or the parser does not support.
+ """
+
+
+class GedcomVersionUnsupportedError(Exception):
+ """Raised when a particular GEDCOM version is not supported
+ by the parser and the standard for that version requires the
+ parser to reject it.
+ """
+
+
+class GedcomFormatUnsupportedError(Exception):
+ """Raised if the GEDCOM format is not recognized by the
+ parser. Note some common misspellings as documented on page 148
+ in the 5.5.5 GEDCOM standard are treated as `LINEAGE-LINKED`
+ and allowed when parsing older GEDCOM data.
+ """
+
+
+class NotAnActualIndividualError(Exception):
+ """Raised if record does not appear to be an `INDIVIDUAL_RECORD`"""
+
+
+class NotAnActualFamilyError(Exception):
+ """Raised if record does not appear to be a `FAM_RECORD`"""
+
+
+class NotAnActualSourceError(Exception):
+ """Raised if record does not appear to be a `SOURCE_RECORD`"""
+
+
+class NotAnActualRepositoryError(Exception):
+ """Raised if record does not appear to be a `REPOSITORY_RECORD`"""
+
+
+class NotAnActualNoteError(Exception):
+ """Raised if record does not appear to be a `NOTE_RECORD`"""
+
+
+class NotAnActualObjectError(Exception):
+ """Raised if record does not appear to be a `MULTIMEDIA_RECORD`"""
+
+
+class NotAnActualHeaderError(Exception):
+ """Raised if record does not appear to be a `HEADER`"""
+
+
+class NotAnActualSubmitterError(Exception):
+ """Raised if record does not appear to be a `SUBMITTER_RECORD`"""
+
+
+class NotAnActualSubmissionError(Exception):
+ """Raised if record does not appear to be a `SUBMISSION_RECORD`"""
diff --git a/gedcom/gedcom.md b/gedcom/gedcom.md
index 56076be..e09365a 100644
--- a/gedcom/gedcom.md
+++ b/gedcom/gedcom.md
@@ -82,6 +82,7 @@ Disabling strict parsing will allow the parser to gracefully handle the followin
Licensed under the [GNU General Public License v2](http://www.gnu.org/licenses/gpl-2.0.html)
**Python GEDCOM Parser**
+ Copyright (C) 2020 Christopher Horn (cdhorn at embarqmail dot com)
Copyright (C) 2018 Damon Brodie (damon.brodie at gmail.com)
Copyright (C) 2018-2019 Nicklas Reincke (contact at reynke.com)
Copyright (C) 2016 Andreas Oberritter
diff --git a/gedcom/parser.py b/gedcom/parser.py
index 473ad9e..c0eeea1 100644
--- a/gedcom/parser.py
+++ b/gedcom/parser.py
@@ -2,6 +2,7 @@
# Python GEDCOM Parser
#
+# Copyright (C) 2020 Christopher Horn (cdhorn at embarqmail dot com)
# Copyright (C) 2018 Damon Brodie (damon.brodie at gmail.com)
# Copyright (C) 2018-2019 Nicklas Reincke (contact at reynke.com)
# Copyright (C) 2016 Andreas Oberritter
@@ -26,35 +27,63 @@
# Further information about the license: http://www.gnu.org/licenses/gpl-2.0.html
"""
-Module containing the actual `gedcom.parser.Parser` used to generate elements - out of each line -
-which can in return be manipulated.
+Module containing the actual `gedcom.parser.Parser` used to generate elements
+out of each line - which can in return be manipulated.
"""
import re as regex
+from sys import stdout
from sys import version_info
+from typing import Tuple, List, IO
+
+import gedcom.tags as tags
+import gedcom.standards as standards
+
+from gedcom.detect import get_encoding, get_version
from gedcom.element.element import Element
-from gedcom.element.family import FamilyElement, NotAnActualFamilyError
-from gedcom.element.file import FileElement
-from gedcom.element.individual import IndividualElement, NotAnActualIndividualError
+from gedcom.element.header import HeaderElement
+from gedcom.element.family import FamilyElement
+from gedcom.element.individual import IndividualElement
+from gedcom.element.note import NoteElement
from gedcom.element.object import ObjectElement
+from gedcom.element.source import SourceElement
+from gedcom.element.submission import SubmissionElement
+from gedcom.element.submitter import SubmitterElement
+from gedcom.element.repository import RepositoryElement
from gedcom.element.root import RootElement
-import gedcom.tags
+
+from gedcom.errors import GedcomVersionUnsupportedError
+from gedcom.errors import GedcomFormatUnsupportedError
+from gedcom.errors import GedcomFormatViolationError
+from gedcom.errors import NotAnActualIndividualError
+from gedcom.errors import NotAnActualFamilyError
+
+ERROR_TEMPLATE = "Line <{0}:{1}> of document violates GEDCOM format {2}\nSee: {3}"
+
+RECORD_ELEMENTS = {
+ tags.GEDCOM_TAG_HEADER: HeaderElement,
+ tags.GEDCOM_TAG_INDIVIDUAL: IndividualElement,
+ tags.GEDCOM_TAG_FAMILY: FamilyElement,
+ tags.GEDCOM_TAG_NOTE: NoteElement,
+ tags.GEDCOM_TAG_OBJECT: ObjectElement,
+ tags.GEDCOM_TAG_SOURCE: SourceElement,
+ tags.GEDCOM_TAG_SUBMISSION: SubmissionElement,
+ tags.GEDCOM_TAG_SUBMITTER: SubmitterElement,
+ tags.GEDCOM_TAG_REPOSITORY: RepositoryElement
+}
FAMILY_MEMBERS_TYPE_ALL = "ALL"
-FAMILY_MEMBERS_TYPE_CHILDREN = gedcom.tags.GEDCOM_TAG_CHILD
-FAMILY_MEMBERS_TYPE_HUSBAND = gedcom.tags.GEDCOM_TAG_HUSBAND
+FAMILY_MEMBERS_TYPE_CHILDREN = tags.GEDCOM_TAG_CHILD
+FAMILY_MEMBERS_TYPE_HUSBAND = tags.GEDCOM_TAG_HUSBAND
FAMILY_MEMBERS_TYPE_PARENTS = "PARENTS"
-FAMILY_MEMBERS_TYPE_WIFE = gedcom.tags.GEDCOM_TAG_WIFE
-
+FAMILY_MEMBERS_TYPE_WIFE = tags.GEDCOM_TAG_WIFE
-class GedcomFormatViolationError(Exception):
- pass
+class Parser():
+ """Parses and manipulates GEDCOM formatted data.
-class Parser(object):
- """Parses and manipulates GEDCOM 5.5 format data
-
- For documentation of the GEDCOM 5.5 format, see: http://homepages.rootsweb.ancestry.com/~pmcbride/gedcom/55gctoc.htm
+ For documentation of the different GEDCOM standards see the
+ links defined in `gedcom.standards`
This parser reads and parses a GEDCOM file.
@@ -70,35 +99,36 @@ def __init__(self):
self.__root_element = RootElement()
def invalidate_cache(self):
- """Empties the element list and dictionary to cause `gedcom.parser.Parser.get_element_list()`
- and `gedcom.parser.Parser.get_element_dictionary()` to return updated data.
+ """Empties the element list and dictionary to cause
+ `gedcom.parser.Parser.get_element_list()` and
+ `gedcom.parser.Parser.get_element_dictionary()` to return updated data.
The update gets deferred until each of the methods actually gets called.
"""
self.__element_list = []
self.__element_dictionary = {}
- def get_element_list(self):
- """Returns a list containing all elements from within the GEDCOM file
+ def get_element_list(self) -> List[Element]:
+ """Returns a list containing all elements from within the GEDCOM file.
By default elements are in the same order as they appeared in the file.
This list gets generated on-the-fly, but gets cached. If the database
- was modified, you should call `gedcom.parser.Parser.invalidate_cache()` once to let this
- method return updated data.
+ was modified, you should call `gedcom.parser.Parser.invalidate_cache()` once
+ to let this method return updated data.
- Consider using `gedcom.parser.Parser.get_root_element()` or `gedcom.parser.Parser.get_root_child_elements()` to access
+ Consider using `gedcom.parser.Parser.get_root_element()` or
+ `gedcom.parser.Parser.get_root_child_elements()` to access
the hierarchical GEDCOM tree, unless you rarely modify the database.
-
- :rtype: list of Element
"""
if not self.__element_list:
for element in self.get_root_child_elements():
self.__build_list(element, self.__element_list)
return self.__element_list
- def get_element_dictionary(self):
- """Returns a dictionary containing all elements, identified by a pointer, from within the GEDCOM file
+ def get_element_dictionary(self) -> dict:
+ """Returns a dictionary containing all elements, identified by a pointer,
+ from within the GEDCOM file.
Only elements identified by a pointer are listed in the dictionary.
The keys for the dictionary are the pointers.
@@ -106,46 +136,51 @@ def get_element_dictionary(self):
This dictionary gets generated on-the-fly, but gets cached. If the
database was modified, you should call `invalidate_cache()` once to let
this method return updated data.
-
- :rtype: dict of Element
"""
if not self.__element_dictionary:
self.__element_dictionary = {
- element.get_pointer(): element for element in self.get_root_child_elements() if element.get_pointer()
+ element.get_pointer():
+ element for element in self.get_root_child_elements() if element.get_pointer()
}
return self.__element_dictionary
- def get_root_element(self):
- """Returns a virtual root element containing all logical records as children
+ def get_root_element(self) -> RootElement:
+ """Returns a virtual root element containing all logical records as children.
When printed, this element converts to an empty string.
-
- :rtype: RootElement
"""
return self.__root_element
- def get_root_child_elements(self):
- """Returns a list of logical records in the GEDCOM file
+ def get_root_child_elements(self) -> List[Element]:
+ """Returns a list of logical records in the GEDCOM file.
By default, elements are in the same order as they appeared in the file.
-
- :rtype: list of Element
"""
return self.get_root_element().get_child_elements()
- def parse_file(self, file_path, strict=True):
- """Opens and parses a file, from the given file path, as GEDCOM 5.5 formatted data
- :type file_path: str
- :type strict: bool
+ def parse_file(self, file_path: str, strict: bool = True):
+ """Opens and parses a file, from the given file path, as GEDCOM formatted data.
"""
- with open(file_path, 'rb') as gedcom_stream:
+ codec = get_encoding(file_path)
+ real_version, reported_version, reported_format = get_version(file_path, codec)
+
+ if reported_version == '5.5.5':
+ errmsg = "This parser does not properly support the GEDCOM " + reported_version + \
+ " standard at this time\nSee: {0}".format(standards.GEDCOM_5_5_5)
+ raise GedcomVersionUnsupportedError(errmsg)
+
+ if reported_format not in ['LINEAGE-LINKED', 'LINEAGE_LINKED',
+ 'LINAGE-LINKED', 'Lineage - Linked']:
+ errmsg = "This parser does not recognize the GEDCOM format " + reported_format + \
+ " at this time\nSee: {0}".format(standards.GEDCOM_5_5_5)
+ raise GedcomFormatUnsupportedError(errmsg)
+
+ with open(file_path, 'r', encoding=codec) as gedcom_stream:
self.parse(gedcom_stream, strict)
- def parse(self, gedcom_stream, strict=True):
- """Parses a stream, or an array of lines, as GEDCOM 5.5 formatted data
- :type gedcom_stream: a file stream, or str array of lines with new line at the end
- :type strict: bool
+ def parse(self, gedcom_stream: IO, strict: bool = True):
+ """Parses a stream, or an array of lines, as GEDCOM formatted data.
"""
self.invalidate_cache()
self.__root_element = RootElement()
@@ -154,24 +189,18 @@ def parse(self, gedcom_stream, strict=True):
last_element = self.get_root_element()
for line in gedcom_stream:
- last_element = self.__parse_line(line_number, line.decode('utf-8-sig'), last_element, strict)
+ last_element = self.__parse_line(line_number, line, last_element, strict)
line_number += 1
# Private methods
@staticmethod
- def __parse_line(line_number, line, last_element, strict=True):
- """Parse a line from a GEDCOM 5.5 formatted document
+ def __parse_line(line_number: int, line: str, last_element: Element,
+ strict: bool = True) -> Element:
+ """Parse a line from a GEDCOM 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.
@@ -190,43 +219,43 @@ def __parse_line(line_number, line, last_element, strict=True):
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
+ 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:%s> of document violates GEDCOM format 5.5" % (line_number, line)
- + "\nSee: https://chronoplexsoftware.com/gedcomvalidator/gedcom/gedcom-5.5.pdf")
- raise GedcomFormatViolationError(error_message)
+ errmsg = ERROR_TEMPLATE.format(line_number, line, '5.5.1', standards.GEDCOM_5_5_1)
+ raise GedcomFormatViolationError(errmsg)
+
+ # 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 - 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
+ # 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 not in [tags.GEDCOM_TAG_CONTINUED, tags.GEDCOM_TAG_CONCATENATION]:
+ # Increment level and change this line to a CONC
+ level += 1
+ tag = tags.GEDCOM_TAG_CONCATENATION
else:
line_parts = regex_match.groups()
@@ -238,20 +267,14 @@ def __parse_line(line_number, line, last_element, strict=True):
# 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)
+ errmsg = "Line {0} of document violates GEDCOM format 5.5.1\n".format(line_number) + \
+ "Lines must be no more than one level higher than previous line.\n" + \
+ "See: {0}".format(standards.GEDCOM_5_5_1)
+ raise GedcomFormatViolationError(errmsg)
# 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)
+ if tag in RECORD_ELEMENTS:
+ element = RECORD_ELEMENTS[tag](level, pointer, tag, value, crlf, multi_line=False)
else:
element = Element(level, pointer, tag, value, crlf, multi_line=False)
@@ -266,10 +289,8 @@ def __parse_line(line_number, line, last_element, strict=True):
return element
- def __build_list(self, element, element_list):
- """Recursively add elements to a list containing elements
- :type element: Element
- :type element_list: list of Element
+ def __build_list(self, element: Element, element_list: List[Element]):
+ """Recursively add elements to a list containing elements.
"""
element_list.append(element)
for child in element.get_child_elements():
@@ -277,81 +298,74 @@ def __build_list(self, element, element_list):
# Methods for analyzing individuals and relationships between individuals
- 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
+ def get_marriages(self, individual: IndividualElement) -> Tuple[str, str]:
+ """Returns a list of marriages of an individual formatted as a tuple:
+ (`str` date, `str` place)
"""
marriages = []
if not isinstance(individual, IndividualElement):
raise NotAnActualIndividualError(
- "Operation only valid for elements with %s tag" % gedcom.tags.GEDCOM_TAG_INDIVIDUAL
+ "Operation only valid for elements with %s tag" % tags.GEDCOM_TAG_INDIVIDUAL
)
# Get and analyze families where individual is spouse.
- families = self.get_families(individual, gedcom.tags.GEDCOM_TAG_FAMILY_SPOUSE)
+ families = self.get_families(individual, 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:
+ if family_data.get_tag() == 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:
+ if marriage_data.get_tag() == tags.GEDCOM_TAG_DATE:
date = marriage_data.get_value()
- if marriage_data.get_tag() == gedcom.tags.GEDCOM_TAG_PLACE:
+ if marriage_data.get_tag() == tags.GEDCOM_TAG_PLACE:
place = marriage_data.get_value()
marriages.append((date, place))
return marriages
- def get_marriage_years(self, individual):
- """Returns a list of marriage years (as integers) for an individual
- :type individual: IndividualElement
- :rtype: list of int
+ def get_marriage_years(self, individual: IndividualElement) -> List[int]:
+ """Returns a list of marriage years for an individual.
"""
dates = []
if not isinstance(individual, IndividualElement):
raise NotAnActualIndividualError(
- "Operation only valid for elements with %s tag" % gedcom.tags.GEDCOM_TAG_INDIVIDUAL
+ "Operation only valid for elements with %s tag" % tags.GEDCOM_TAG_INDIVIDUAL
)
# Get and analyze families where individual is spouse.
- families = self.get_families(individual, gedcom.tags.GEDCOM_TAG_FAMILY_SPOUSE)
+ families = self.get_families(individual, 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]
+ if child.get_tag() == tags.GEDCOM_TAG_MARRIAGE:
+ for gchild in child.get_child_elements():
+ if gchild.get_tag() == tags.GEDCOM_TAG_DATE:
+ date = gchild.get_value().split()[-1]
try:
dates.append(int(date))
except ValueError:
pass
return dates
- 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
+ def marriage_year_match(self, individual: IndividualElement, year: int) -> bool:
+ """Checks if one of the marriage years of an individual matches the supplied year.
+ Year is an integer.
"""
if not isinstance(individual, IndividualElement):
raise NotAnActualIndividualError(
- "Operation only valid for elements with %s tag" % gedcom.tags.GEDCOM_TAG_INDIVIDUAL
+ "Operation only valid for elements with %s tag" % 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
+ def marriage_range_match(self, individual: IndividualElement,
+ from_year: int, to_year: int) -> bool:
+ """Check if one of the marriage years of an individual is in a given range.
+ Years are integers.
"""
if not isinstance(individual, IndividualElement):
raise NotAnActualIndividualError(
- "Operation only valid for elements with %s tag" % gedcom.tags.GEDCOM_TAG_INDIVIDUAL
+ "Operation only valid for elements with %s tag" % tags.GEDCOM_TAG_INDIVIDUAL
)
years = self.get_marriage_years(individual)
@@ -360,20 +374,19 @@ def marriage_range_match(self, individual, from_year, to_year):
return True
return False
- def get_families(self, individual, family_type=gedcom.tags.GEDCOM_TAG_FAMILY_SPOUSE):
- """Return family elements listed for an individual
+ def get_families(self, individual: IndividualElement,
+ family_type: str = tags.GEDCOM_TAG_FAMILY_SPOUSE) -> List[FamilyElement]:
+ """Return family elements listed for an individual.
+
+ Optional argument `family_type` can be used to return specific subsets:
- 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.
+ `tags.GEDCOM_TAG_FAMILY_SPOUSE`: Default, families where the individual is a spouse.
- :type individual: IndividualElement
- :type family_type: str
- :rtype: list of FamilyElement
+ `tags.GEDCOM_TAG_FAMILY_CHILD`: Families where the individual is a child.
"""
if not isinstance(individual, IndividualElement):
raise NotAnActualIndividualError(
- "Operation only valid for elements with %s tag" % gedcom.tags.GEDCOM_TAG_INDIVIDUAL
+ "Operation only valid for elements with %s tag" % tags.GEDCOM_TAG_INDIVIDUAL
)
families = []
@@ -388,19 +401,19 @@ def get_families(self, individual, family_type=gedcom.tags.GEDCOM_TAG_FAMILY_SPO
return families
- def get_ancestors(self, individual, ancestor_type="ALL"):
- """Return elements corresponding to ancestors of an individual
+ def get_ancestors(self, individual: IndividualElement,
+ ancestor_type: str = "ALL") -> List[Element]:
+ """Return elements corresponding to ancestors of an individual.
+
+ Optional argument `ancestor_type` can be used to return specific subsets:
- Optional `ancestor_type`. Default "ALL" returns all ancestors, "NAT" can be
- used to specify only natural (genetic) ancestors.
+ "ALL": Default, returns all ancestors.
- :type individual: IndividualElement
- :type ancestor_type: str
- :rtype: list of Element
+ "NAT": Return only natural (genetic) ancestors.
"""
if not isinstance(individual, IndividualElement):
raise NotAnActualIndividualError(
- "Operation only valid for elements with %s tag" % gedcom.tags.GEDCOM_TAG_INDIVIDUAL
+ "Operation only valid for elements with %s tag" % tags.GEDCOM_TAG_INDIVIDUAL
)
parents = self.get_parents(individual, ancestor_type)
@@ -412,49 +425,53 @@ def get_ancestors(self, individual, ancestor_type="ALL"):
return ancestors
- def get_parents(self, individual, parent_type="ALL"):
- """Return elements corresponding to parents of an individual
+ def get_parents(self, individual: IndividualElement,
+ parent_type: str = "ALL") -> List[IndividualElement]:
+ """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.
+ Optional argument `parent_type` can be used to return specific subsets:
- :type individual: IndividualElement
- :type parent_type: str
- :rtype: list of IndividualElement
+ "ALL": Default, returns all parents.
+
+ "NAT": Return only natural (genetic) parents.
"""
if not isinstance(individual, IndividualElement):
raise NotAnActualIndividualError(
- "Operation only valid for elements with %s tag" % gedcom.tags.GEDCOM_TAG_INDIVIDUAL
+ "Operation only valid for elements with %s tag" % tags.GEDCOM_TAG_INDIVIDUAL
)
parents = []
- families = self.get_families(individual, gedcom.tags.GEDCOM_TAG_FAMILY_CHILD)
+ families = self.get_families(individual, 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 \
+ if family_member.get_tag() == 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)
+ if child.get_tag() == tags.GEDCOM_PROGRAM_DEFINED_TAG_MREL:
+ parents += self.get_family_members(family,
+ tags.GEDCOM_TAG_WIFE)
+ elif child.get_tag() == tags.GEDCOM_PROGRAM_DEFINED_TAG_FREL:
+ parents += self.get_family_members(family,
+ tags.GEDCOM_TAG_HUSBAND)
else:
parents += self.get_family_members(family, "PARENTS")
return parents
- def find_path_to_ancestor(self, descendant, ancestor, path=None):
- """Return path from descendant to ancestor
+ def find_path_to_ancestor(self, descendant: IndividualElement,
+ ancestor: IndividualElement, path: str = None):
+ """Return path from descendant to ancestor.
:rtype: object
"""
- if not isinstance(descendant, IndividualElement) and isinstance(ancestor, IndividualElement):
+ if not isinstance(descendant, IndividualElement) and isinstance(ancestor,
+ IndividualElement):
raise NotAnActualIndividualError(
- "Operation only valid for elements with %s tag." % gedcom.tags.GEDCOM_TAG_INDIVIDUAL
+ "Operation only valid for elements with %s tag." % tags.GEDCOM_TAG_INDIVIDUAL
)
if not path:
@@ -462,33 +479,34 @@ def find_path_to_ancestor(self, descendant, ancestor, path=None):
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
+
+ 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
- def get_family_members(self, family, members_type=FAMILY_MEMBERS_TYPE_ALL):
- """Return array of family members: individual, spouse, and children
+ def get_family_members(self, family: FamilyElement,
+ members_type: str = FAMILY_MEMBERS_TYPE_ALL) -> List[IndividualElement]:
+ """Return array of family members: individual, spouse, and children.
Optional argument `members_type` can be used to return specific subsets:
"FAMILY_MEMBERS_TYPE_ALL": Default, return all members of the family
+
"FAMILY_MEMBERS_TYPE_PARENTS": Return individuals with "HUSB" and "WIFE" tags (parents)
+
"FAMILY_MEMBERS_TYPE_HUSBAND": Return individuals with "HUSB" tags (father)
+
"FAMILY_MEMBERS_TYPE_WIFE": Return individuals with "WIFE" tags (mother)
- "FAMILY_MEMBERS_TYPE_CHILDREN": Return individuals with "CHIL" tags (children)
- :type family: FamilyElement
- :type members_type: str
- :rtype: list of IndividualElement
+ "FAMILY_MEMBERS_TYPE_CHILDREN": Return individuals with "CHIL" tags (children)
"""
if not isinstance(family, FamilyElement):
raise NotAnActualFamilyError(
- "Operation only valid for element with %s tag." % gedcom.tags.GEDCOM_TAG_FAMILY
+ "Operation only valid for element with %s tag." % tags.GEDCOM_TAG_FAMILY
)
family_members = []
@@ -496,19 +514,19 @@ def get_family_members(self, family, members_type=FAMILY_MEMBERS_TYPE_ALL):
for child_element in family.get_child_elements():
# Default is ALL
- is_family = (child_element.get_tag() == gedcom.tags.GEDCOM_TAG_HUSBAND
- or child_element.get_tag() == gedcom.tags.GEDCOM_TAG_WIFE
- or child_element.get_tag() == gedcom.tags.GEDCOM_TAG_CHILD)
+ is_family = (child_element.get_tag() == tags.GEDCOM_TAG_HUSBAND
+ or child_element.get_tag() == tags.GEDCOM_TAG_WIFE
+ or child_element.get_tag() == tags.GEDCOM_TAG_CHILD)
if members_type == FAMILY_MEMBERS_TYPE_PARENTS:
- is_family = (child_element.get_tag() == gedcom.tags.GEDCOM_TAG_HUSBAND
- or child_element.get_tag() == gedcom.tags.GEDCOM_TAG_WIFE)
+ is_family = (child_element.get_tag() == tags.GEDCOM_TAG_HUSBAND
+ or child_element.get_tag() == tags.GEDCOM_TAG_WIFE)
elif members_type == FAMILY_MEMBERS_TYPE_HUSBAND:
- is_family = child_element.get_tag() == gedcom.tags.GEDCOM_TAG_HUSBAND
+ is_family = child_element.get_tag() == tags.GEDCOM_TAG_HUSBAND
elif members_type == FAMILY_MEMBERS_TYPE_WIFE:
- is_family = child_element.get_tag() == gedcom.tags.GEDCOM_TAG_WIFE
+ is_family = child_element.get_tag() == tags.GEDCOM_TAG_WIFE
elif members_type == FAMILY_MEMBERS_TYPE_CHILDREN:
- is_family = child_element.get_tag() == gedcom.tags.GEDCOM_TAG_CHILD
+ is_family = child_element.get_tag() == tags.GEDCOM_TAG_CHILD
if is_family and child_element.get_value() in element_dictionary:
family_members.append(element_dictionary[child_element.get_value()])
@@ -517,9 +535,9 @@ def get_family_members(self, family, members_type=FAMILY_MEMBERS_TYPE_ALL):
# Other methods
- def to_gedcom_string(self, recursive=False):
- """Formats all elements and optionally all of the sub-elements into a GEDCOM string
- :type recursive: bool
+ def to_gedcom_string(self, recursive: bool = False) -> str:
+ """Formats all elements and optionally all of the sub-elements into a
+ GEDCOM string.
"""
is_gte_python_3 = version_info[0] >= 3
output = '' if is_gte_python_3 else b''
@@ -533,13 +551,10 @@ def to_gedcom_string(self, recursive=False):
return output
def print_gedcom(self):
- """Write GEDCOM data to stdout"""
- from sys import stdout
+ """Write GEDCOM data to stdout."""
self.save_gedcom(stdout)
- def save_gedcom(self, open_file, recursive=True):
- """Save GEDCOM data to a file
- :type open_file: file
- :type recursive: bool
+ def save_gedcom(self, open_file: IO, recursive: bool = True):
+ """Save GEDCOM data to a file.
"""
open_file.write(self.to_gedcom_string(recursive))
diff --git a/gedcom/reader.py b/gedcom/reader.py
new file mode 100644
index 0000000..cac6727
--- /dev/null
+++ b/gedcom/reader.py
@@ -0,0 +1,124 @@
+# -*- coding: utf-8 -*-
+
+# Python GEDCOM Parser
+#
+# Copyright (C) 2020 Christopher Horn (cdhorn at embarqmail dot com)
+# Copyright (C) 2018 Damon Brodie (damon.brodie at gmail.com)
+# Copyright (C) 2018-2019 Nicklas Reincke (contact at reynke.com)
+# Copyright (C) 2016 Andreas Oberritter
+# Copyright (C) 2012 Madeleine Price Ball
+# Copyright (C) 2005 Daniel Zappala (zappala at cs.byu.edu)
+# Copyright (C) 2005 Brigham Young University
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Further information about the license: http://www.gnu.org/licenses/gpl-2.0.html
+
+"""
+Module containing a `gedcom.reader.Reader` with higher order methods than the
+base `gedcom.parser.Parser` for extracting records as structured data.
+"""
+
+from typing import Union
+
+from gedcom.parser import Parser
+from gedcom.element.header import HeaderElement
+from gedcom.element.individual import IndividualElement
+from gedcom.element.family import FamilyElement
+from gedcom.element.note import NoteElement
+from gedcom.element.object import ObjectElement
+from gedcom.element.source import SourceElement
+from gedcom.element.submission import SubmissionElement
+from gedcom.element.submitter import SubmitterElement
+from gedcom.element.repository import RepositoryElement
+
+ELEMENT_TYPES = {
+ 'header': HeaderElement,
+ 'individual': IndividualElement,
+ 'family': FamilyElement,
+ 'note': NoteElement,
+ 'media': ObjectElement,
+ 'source': SourceElement,
+ 'submission': SubmissionElement,
+ 'submitter': SubmitterElement,
+ 'repository': RepositoryElement
+}
+
+RECORD_KEYS = {
+ 'header': None,
+ 'individual': 'key_to_individual',
+ 'family': 'key_to_family',
+ 'media': 'key_to_object',
+ 'note': 'key_to_note',
+ 'source': 'key_to_source',
+ 'submission': 'key_to_submission',
+ 'submitter': 'key_to_submitter',
+ 'repository': 'key_to_repository'
+}
+
+
+class Reader(Parser):
+ """Simple wrapper around the core `gedcom.parser.Parser` with methods for
+ extracting parsed records as structured data.
+ """
+
+ def get_records_by_type(self, record_type: str,
+ return_output_as_list: bool = True) -> Union[list, dict]:
+ """Return either a list or dictionary with all of the requested records for the
+ given `gedcom.records` record type.
+ """
+ record_list = []
+ record_dict = {}
+
+ for element in self.get_root_child_elements():
+ if isinstance(element, ELEMENT_TYPES[record_type]):
+ record = element.get_record()
+ if return_output_as_list:
+ record_list.append(record)
+ else:
+ if RECORD_KEYS[record_type] is not None:
+ record_dict.update({record[RECORD_KEYS[record_type]]: record})
+ else:
+ record_dict.update({'@HEAD@': record})
+
+ if return_output_as_list:
+ return record_list
+
+ return record_dict
+
+ def get_all_records(self, return_entries_as_list: bool = True) -> dict:
+ """Return a dictionary with all of the available records in the GEDCOM broken
+ down by record type."""
+ record_dict = {}
+
+ for key in RECORD_KEYS:
+ if return_entries_as_list:
+ record_dict.update({key: []})
+ else:
+ record_dict.update({key: {}})
+
+ for element in self.get_root_child_elements():
+ for key in ELEMENT_TYPES:
+ if isinstance(element, ELEMENT_TYPES[key]):
+ record = element.get_record()
+ if return_entries_as_list:
+ record_dict[key].append(record)
+ else:
+ if key != 'header':
+ record_dict[key].update({record[RECORD_KEYS[key]]: record})
+ else:
+ record_dict['header'].update({'@HEAD@': record})
+
+ return record_dict
diff --git a/gedcom/records.py b/gedcom/records.py
new file mode 100644
index 0000000..a2ae70f
--- /dev/null
+++ b/gedcom/records.py
@@ -0,0 +1,55 @@
+# -*- coding: utf-8 -*-
+
+# Python GEDCOM Parser
+#
+# Copyright (C) 2020 Christopher Horn (cdhorn at embarqmail dot com)
+# Copyright (C) 2018 Damon Brodie (damon.brodie at gmail.com)
+# Copyright (C) 2018-2019 Nicklas Reincke (contact at reynke.com)
+# Copyright (C) 2016 Andreas Oberritter
+# Copyright (C) 2012 Madeleine Price Ball
+# Copyright (C) 2005 Daniel Zappala (zappala at cs.byu.edu)
+# Copyright (C) 2005 Brigham Young University
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Further information about the license: http://www.gnu.org/licenses/gpl-2.0.html
+
+"""Module containing the standard GEDCOM record types recognized by the
+GEDCOM `gedcom.reader.Reader`."""
+
+
+GEDCOM_RECORD_FAMILY = 'family'
+"""Identifies the `FAM_RECORD` record type."""
+
+GEDCOM_RECORD_HEADER = 'header'
+"""Identifies the `HEADER` record type."""
+
+GEDCOM_RECORD_INDIVIDUAL = 'individual'
+"""Identifies the `INDIVIDUAL_RECORD` record type."""
+
+GEDCOM_RECORD_NOTE = 'note'
+"""Identifies the `NOTE_RECORD` record type."""
+
+GEDCOM_RECORD_SOURCE = 'source'
+"""Identifies the `SOURCE_RECORD` record type."""
+
+GEDCOM_RECORD_REPOSITORY = 'repository'
+"""Identifies the `REPOSITORY_RECORD` record type."""
+
+GEDCOM_RECORD_SUBMISSION = 'submission'
+"""Identifies the `SUBMISSION_RECORD` record type."""
+
+GEDCOM_RECORD_SUBMITTER = 'submitter'
+"""Identifies the `SUBMITTER_RECORD` record type."""
diff --git a/gedcom/element/file.py b/gedcom/standards.py
similarity index 59%
rename from gedcom/element/file.py
rename to gedcom/standards.py
index d02e8eb..7bbd9b1 100644
--- a/gedcom/element/file.py
+++ b/gedcom/standards.py
@@ -2,6 +2,7 @@
# Python GEDCOM Parser
#
+# Copyright (C) 2020 Christopher Horn (cdhorn at embarqmail dot com)
# Copyright (C) 2018 Damon Brodie (damon.brodie at gmail.com)
# Copyright (C) 2018-2019 Nicklas Reincke (contact at reynke.com)
# Copyright (C) 2016 Andreas Oberritter
@@ -25,17 +26,19 @@
#
# Further information about the license: http://www.gnu.org/licenses/gpl-2.0.html
-"""GEDCOM element consisting of tag `gedcom.tags.GEDCOM_TAG_FILE`"""
+"""Module containing links to the documentation for the various GEDCOM standards."""
-from gedcom.element.element import Element
-import gedcom.tags
+GEDCOM_5_5 = "https://edge.fscdn.org/assets/img/documents/" + \
+ "gedcom55-82e1509bd8dbe7477e3b500e4f62c240.pdf"
+"""The official FamilySearch GEDCOM 5.5 Standard."""
+GEDCOM_5_5_1 = "https://edge.fscdn.org/assets/img/documents/" + \
+ "ged551-5bac5e57fe88dd37df0e153d9c515335.pdf"
+"""The official FamilySearch GEDCOM 5.5.1 Standard."""
-class NotAnActualFileError(Exception):
- pass
+GEDCOM_5_5_1_GEDCOM_L_ADDENDUM = "https://genealogy.net/GEDCOM/" + \
+ "GEDCOM551%20GEDCOM-L%20Addendum-R1.pdf"
+"""The GEDCOM-L working group GEDCOM 5.5.1 Addendum."""
-
-class FileElement(Element):
-
- def get_tag(self):
- return gedcom.tags.GEDCOM_TAG_FILE
+GEDCOM_5_5_5 = "https://www.gedcom.org/specs/GEDCOM555.zip"
+"""The gedcom.org GEDCOM 5.5.5 Specification With Annotations."""
diff --git a/gedcom/subparsers/__init__.py b/gedcom/subparsers/__init__.py
new file mode 100644
index 0000000..69162ac
--- /dev/null
+++ b/gedcom/subparsers/__init__.py
@@ -0,0 +1,48 @@
+# -*- coding: utf-8 -*-
+
+# Python GEDCOM Parser
+#
+# Copyright (C) 2020 Christopher Horn (cdhorn at embarqmail dot com)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Further information about the license: http://www.gnu.org/licenses/gpl-2.0.html
+
+"""Module containing parsers for extracting various substructures from the
+different record types as defined in the GEDCOM standard."""
+
+__all__ = [
+ "address_structure",
+ "association_structure",
+ "change_date",
+ "child_to_family_link",
+ "event_detail",
+ "family_event_detail",
+ "family_event_structure",
+ "individual_attribute_structure",
+ "individual_event_detail",
+ "individual_event_structure",
+ "lds_individual_ordinance",
+ "lds_spouse_sealing",
+ "multimedia_link",
+ "note_structure",
+ "personal_name_pieces",
+ "personal_name_structure",
+ "place_structure",
+ "source_citation",
+ "source_repository_citation",
+ "spouse_to_family_link",
+ "user_reference_number"
+]
diff --git a/gedcom/subparsers/address_structure.py b/gedcom/subparsers/address_structure.py
new file mode 100644
index 0000000..873c8c4
--- /dev/null
+++ b/gedcom/subparsers/address_structure.py
@@ -0,0 +1,84 @@
+# -*- coding: utf-8 -*-
+
+# Python GEDCOM Parser
+#
+# Copyright (C) 2020 Christopher Horn (cdhorn at embarqmail dot com)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Further information about the license: http://www.gnu.org/licenses/gpl-2.0.html
+
+"""
+Substructure parser for a `ADDRESS_STRUCTURE` embedded record.
+
+This is referenced as part of a larger structure so there is no anchor tag.
+The `gedcom.tags.GEDCOM_TAG_ADDRESS` tag is at the same level as some of
+the other parts of this structure.
+"""
+
+import gedcom.tags as tags
+from gedcom.element.element import Element
+
+ADDRESS_TAGS = {
+ tags.GEDCOM_PROGRAM_DEFINED_TAG_ADDRESSE: 'addresse',
+ tags.GEDCOM_TAG_ADDRESS1: 'address1',
+ tags.GEDCOM_TAG_ADDRESS2: 'address2',
+ tags.GEDCOM_TAG_ADDRESS3: 'address3',
+ tags.GEDCOM_TAG_CITY: 'city',
+ tags.GEDCOM_TAG_STATE: 'state',
+ tags.GEDCOM_TAG_POSTAL_CODE: 'postal_code',
+ tags.GEDCOM_TAG_COUNTRY: 'country'
+}
+
+CONTACT_TAGS = {
+ tags.GEDCOM_TAG_PHONE: 'phone',
+ tags.GEDCOM_TAG_EMAIL: 'email',
+ tags.GEDCOM_TAG_FAX: 'fax',
+ tags.GEDCOM_TAG_WWW: 'www'
+}
+
+
+def address_structure(element: Element) -> dict:
+ """Parses and extracts a `ADDRESS_STRUCTURE` structure.
+
+ The `element` should be the parent that contains it.
+ """
+ record = {
+ 'address': '',
+ 'addresse': '',
+ 'address1': '',
+ 'address2': '',
+ 'address3': '',
+ 'city': '',
+ 'state': '',
+ 'postal_code': '',
+ 'country': '',
+ 'phone': [],
+ 'email': [],
+ 'fax': [],
+ 'www': []
+ }
+ for child in element.get_child_elements():
+ if child.get_tag() == tags.GEDCOM_TAG_ADDRESS:
+ record['address'] = child.get_multi_line_value()
+ for gchild in child.get_child_elements():
+ if gchild.get_tag() in ADDRESS_TAGS:
+ record[ADDRESS_TAGS[gchild.get_tag()]] = gchild.get_value()
+ continue
+
+ if child.get_tag() in CONTACT_TAGS:
+ record[CONTACT_TAGS[child.get_tag()]].append(child.get_value())
+
+ return record
diff --git a/gedcom/subparsers/association_structure.py b/gedcom/subparsers/association_structure.py
new file mode 100644
index 0000000..45dd76e
--- /dev/null
+++ b/gedcom/subparsers/association_structure.py
@@ -0,0 +1,58 @@
+# -*- coding: utf-8 -*-
+
+# Python GEDCOM Parser
+#
+# Copyright (C) 2020 Christopher Horn (cdhorn at embarqmail dot com)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Further information about the license: http://www.gnu.org/licenses/gpl-2.0.html
+
+"""
+Substructure parser for the `ASSOCIATION_STRUCTURE` record.
+
+This is anchored by the `gedcom.tags.GEDCOM_TAG_ASSOCIATES` tag.
+"""
+
+import gedcom.tags as tags
+from gedcom.element.element import Element
+from gedcom.subparsers.note_structure import note_structure
+from gedcom.subparsers.source_citation import source_citation
+
+
+def association_structure(element: Element) -> dict:
+ """Parses and extracts the `ASSOCIATION_STRUCTURE` structure.
+
+ The `element` should contain the `gedcom.tags.GEDCOM_TAG_ASSOCIATES` tag.
+ """
+ record = {
+ 'key_to_individual': element.get_value(),
+ 'relationship': '',
+ 'citations': [],
+ 'notes': []
+ }
+ for child in element.get_child_elements():
+ if child.get_tag() == tags.GEDCOM_TAG_RELATIONSHIP:
+ record['relationship'] = child.get_value()
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_NOTE:
+ record['notes'].append(note_structure(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_SOURCE:
+ record['citations'].append(source_citation(child))
+
+ return record
diff --git a/gedcom/subparsers/change_date.py b/gedcom/subparsers/change_date.py
new file mode 100644
index 0000000..f53823d
--- /dev/null
+++ b/gedcom/subparsers/change_date.py
@@ -0,0 +1,56 @@
+# -*- coding: utf-8 -*-
+
+# Python GEDCOM Parser
+#
+# Copyright (C) 2020 Christopher Horn (cdhorn at embarqmail dot com)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Further information about the license: http://www.gnu.org/licenses/gpl-2.0.html
+
+"""
+Substructure parser for a `CHANGE_DATE` record.
+
+This is anchored by the `gedcom.tags.GEDCOM_TAG_CHANGE` tag.
+"""
+
+import gedcom.tags as tags
+from gedcom.element.element import Element
+from gedcom.subparsers.note_structure import note_structure
+
+
+def change_date(element: Element) -> dict:
+ """Parses and extracts a `CHANGE_DATE` structure.
+
+ The `element` should contain the `gedcom.tags.GEDCOM_TAG_CHANGE` tag.
+ """
+ record = {
+ 'date': '',
+ 'time': '',
+ 'notes': []
+ }
+ for child in element.get_child_elements():
+ if child.get_tag() == tags.GEDCOM_TAG_DATE:
+ record['date'] = child.get_value()
+ for gchild in child.get_child_elements():
+ if gchild.get_tag() == tags.GEDCOM_TAG_TIME:
+ record['time'] = gchild.get_value()
+ continue
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_NOTE:
+ record['notes'].append(note_structure(child))
+
+ return record
diff --git a/gedcom/subparsers/child_to_family_link.py b/gedcom/subparsers/child_to_family_link.py
new file mode 100644
index 0000000..8f63141
--- /dev/null
+++ b/gedcom/subparsers/child_to_family_link.py
@@ -0,0 +1,57 @@
+# -*- coding: utf-8 -*-
+
+# Python GEDCOM Parser
+#
+# Copyright (C) 2020 Christopher Horn (cdhorn at embarqmail dot com)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Further information about the license: http://www.gnu.org/licenses/gpl-2.0.html
+
+"""
+Substructure parser for a `CHILD_TO_FAMILY_LINK` record.
+
+This is anchored by the `gedcom.tags.GEDCOM_TAG_FAMILY_CHILD` tag.
+"""
+
+import gedcom.tags as tags
+from gedcom.element.element import Element
+from gedcom.subparsers.note_structure import note_structure
+
+
+def child_to_family_link(element: Element) -> dict:
+ """Parses and extracts a `CHILD_TO_FAMILY_LINK` structure.
+
+ The `element` should contain the `gedcom.tags.GEDCOM_TAG_FAMILY_CHILD` tag.
+ """
+ record = {
+ 'key_to_family': element.get_value(),
+ 'pedigree': '',
+ 'status': '',
+ 'notes': []
+ }
+ for child in element.get_child_elements():
+ if child.get_tag() == tags.GEDCOM_TAG_PEDIGREE:
+ record['pedigree'] = child.get_value()
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_STATUS:
+ record['status'] = child.get_value()
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_NOTE:
+ record['notes'].append(note_structure(child))
+
+ return record
diff --git a/gedcom/subparsers/event_detail.py b/gedcom/subparsers/event_detail.py
new file mode 100644
index 0000000..2dac099
--- /dev/null
+++ b/gedcom/subparsers/event_detail.py
@@ -0,0 +1,89 @@
+# -*- coding: utf-8 -*-
+
+# Python GEDCOM Parser
+#
+# Copyright (C) 2020 Christopher Horn (cdhorn at embarqmail dot com)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Further information about the license: http://www.gnu.org/licenses/gpl-2.0.html
+
+"""
+Substructure parser for a `EVENT_DETAIL` embedded record.
+
+This is referenced as part of a larger structure so there is no anchor tag.
+"""
+
+import gedcom.tags as tags
+from gedcom.element.element import Element
+from gedcom.subparsers.place_structure import place_structure
+from gedcom.subparsers.address_structure import address_structure
+from gedcom.subparsers.note_structure import note_structure
+from gedcom.subparsers.source_citation import source_citation
+from gedcom.subparsers.multimedia_link import multimedia_link
+
+EVENT_TAGS = {
+ tags.GEDCOM_TAG_TYPE: 'type',
+ tags.GEDCOM_TAG_DATE: 'date',
+ tags.GEDCOM_TAG_AGENCY: 'responsible_agency',
+ tags.GEDCOM_TAG_RELIGION: 'religious_affiliation',
+ tags.GEDCOM_TAG_CAUSE: 'cause_of_event',
+ tags.GEDCOM_TAG_RESTRICTION: 'restriction'
+}
+
+
+def event_detail(element: Element) -> dict:
+ """Parses and extracts a `EVENT_DETAIL` structure.
+
+ The `element` should be the parent that contains it.
+ """
+ record = {
+ 'type': '',
+ 'date': '',
+ 'place': {},
+ 'address': {},
+ 'responsible_agency': '',
+ 'religious_affiliation': '',
+ 'cause_of_event': '',
+ 'restriction_notice': '',
+ 'notes': [],
+ 'citations': [],
+ 'media': []
+ }
+ for child in element.get_child_elements():
+ if child.get_tag() in EVENT_TAGS:
+ record[EVENT_TAGS[child.get_tag()]] = child.get_value()
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_PLACE:
+ record['place'] = place_structure(child)
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_ADDRESS:
+ record['address'] = address_structure(element)
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_NOTE:
+ record['notes'].append(note_structure(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_SOURCE:
+ record['citations'].append(source_citation(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_OBJECT:
+ record['media'].append(multimedia_link(child))
+
+ return record
diff --git a/gedcom/subparsers/family_event_detail.py b/gedcom/subparsers/family_event_detail.py
new file mode 100644
index 0000000..4b1ba9b
--- /dev/null
+++ b/gedcom/subparsers/family_event_detail.py
@@ -0,0 +1,54 @@
+# -*- coding: utf-8 -*-
+
+# Python GEDCOM Parser
+#
+# Copyright (C) 2020 Christopher Horn (cdhorn at embarqmail dot com)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Further information about the license: http://www.gnu.org/licenses/gpl-2.0.html
+
+"""
+Substructure parser for a `FAMILY_EVENT_DETAIL` emdedded record.
+
+This is referenced as part of a larger structure so there is no anchor tag.
+"""
+
+import gedcom.tags as tags
+from gedcom.element.element import Element
+from gedcom.subparsers.event_detail import event_detail
+
+
+def family_event_detail(element: Element) -> dict:
+ """Parses and extracts a `FAMILY_EVENT_DETAIL` structure.
+
+ The `element` shouldbe the parent that contains it.
+ """
+ record = event_detail(element)
+ record['husband_age'] = ''
+ record['wife_age'] = ''
+ for child in element.get_child_elements():
+ if child.get_tag() == tags.GEDCOM_TAG_HUSBAND:
+ for gchild in child.get_child_elements():
+ if gchild.get_tag() == tags.GEDCOM_TAG_AGE:
+ record['husband_age'] = gchild.get_value()
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_WIFE:
+ for gchild in child.get_child_elements():
+ if gchild.get_tag() == tags.GEDCOM_TAG_AGE:
+ record['wife_age'] = gchild.get_value()
+
+ return record
diff --git a/gedcom/subparsers/family_event_structure.py b/gedcom/subparsers/family_event_structure.py
new file mode 100644
index 0000000..1dac1af
--- /dev/null
+++ b/gedcom/subparsers/family_event_structure.py
@@ -0,0 +1,65 @@
+# -*- coding: utf-8 -*-
+
+# Python GEDCOM Parser
+#
+# Copyright (C) 2020 Christopher Horn (cdhorn at embarqmail dot com)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Further information about the license: http://www.gnu.org/licenses/gpl-2.0.html
+
+"""
+Substructure parser for a `FAMILY_EVENT_STRUCTURE` embedded record.
+
+This is referenced as part of a larger structure so there is no anchor tag.
+"""
+
+from typing import List
+
+import gedcom.tags as tags
+from gedcom.element.element import Element
+from gedcom.subparsers.family_event_detail import family_event_detail
+
+EVENT_TAGS = {
+ tags.GEDCOM_TAG_ANNULMENT: 'annulment',
+ tags.GEDCOM_TAG_CENSUS: 'census',
+ tags.GEDCOM_TAG_DIVORCE: 'divorce',
+ tags.GEDCOM_TAG_DIVORCE_FILED: 'divorce_filed',
+ tags.GEDCOM_TAG_ENGAGEMENT: 'engagement',
+ tags.GEDCOM_TAG_MARRIAGE: 'marriage',
+ tags.GEDCOM_TAG_MARRIAGE_BANN: 'marriage_bann',
+ tags.GEDCOM_TAG_MARR_CONTRACT: 'marriage_contract',
+ tags.GEDCOM_TAG_MARR_LICENSE: 'marriage_license',
+ tags.GEDCOM_TAG_MARR_SETTLEMENT: 'marriage_settlement',
+ tags.GEDCOM_TAG_RESIDENCE: 'residence',
+ tags.GEDCOM_TAG_EVENT: 'event'
+}
+
+
+def family_event_structure(element: Element) -> List[dict]:
+ """Parses and extracts a `FAMILY_EVENT_STRUCTURE` structure.
+
+ The `element` should be the parent that contains it.
+ """
+ records = []
+ for child in element.get_child_elements():
+ if child.get_tag() in EVENT_TAGS:
+ record = family_event_detail(child)
+ record['description'] = child.get_multi_line_value()
+ record['tag'] = child.get_tag()
+ record['event'] = EVENT_TAGS[child.get_tag()]
+ records.append(record)
+
+ return records
diff --git a/gedcom/subparsers/individual_attribute_structure.py b/gedcom/subparsers/individual_attribute_structure.py
new file mode 100644
index 0000000..43a2d0f
--- /dev/null
+++ b/gedcom/subparsers/individual_attribute_structure.py
@@ -0,0 +1,69 @@
+# -*- coding: utf-8 -*-
+
+# Python GEDCOM Parser
+#
+# Copyright (C) 2020 Christopher Horn (cdhorn at embarqmail dot com)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Further information about the license: http://www.gnu.org/licenses/gpl-2.0.html
+
+"""
+Substructure parser for the `INDIVIDUAL_ATTRIBUTE_STRUCTURE` embedded record.
+
+This is referenced as part of a larger structure so there is no anchor tag.
+"""
+
+from typing import List
+
+import gedcom.tags as tags
+from gedcom.element.element import Element
+from gedcom.subparsers.individual_event_detail import individual_event_detail
+
+ATTRIBUTE_TAGS = {
+ tags.GEDCOM_TAG_CASTE: 'caste',
+ tags.GEDCOM_TAG_PHY_DESCRIPTION: 'physical_description',
+ tags.GEDCOM_TAG_EDUCATION: 'eduction',
+ tags.GEDCOM_TAG_IDENT_NUMBER: 'identity_number',
+ tags.GEDCOM_TAG_NATIONALITY: 'nationality',
+ tags.GEDCOM_TAG_CHILDREN_COUNT: 'number_of_children',
+ tags.GEDCOM_TAG_MARRIAGE_COUNT: 'number_of_marriages',
+ tags.GEDCOM_TAG_OCCUPATION: 'occupation',
+ tags.GEDCOM_TAG_PROPERTY: 'property',
+ tags.GEDCOM_TAG_RELIGION: 'religion',
+ tags.GEDCOM_TAG_RESIDENCE: 'residence',
+ tags.GEDCOM_TAG_SOC_SEC_NUMBER: 'social_security_number',
+ tags.GEDCOM_TAG_TITLE: 'title',
+ tags.GEDCOM_TAG_FACT: 'fact',
+ tags.GEDCOM_PROGRAM_DEFINED_TAG_DCAUSE: 'cause_of_death'
+}
+
+
+def individual_attribute_structure(element: Element) -> List[dict]:
+ """Parses and extracts the `INDIVIDUAL_ATTRIBUTE_STRUCTURE` structures.
+
+ The `element` should be the parent that contains them.
+ """
+ records = []
+ for child in element.get_child_elements():
+ if child.get_tag() in ATTRIBUTE_TAGS:
+ record = individual_event_detail(child)
+ record['description'] = child.get_multi_line_value()
+ record['tag'] = child.get_tag()
+ record['attribute'] = ATTRIBUTE_TAGS[child.get_tag()]
+ records.append(record)
+ continue
+
+ return records
diff --git a/gedcom/subparsers/individual_event_detail.py b/gedcom/subparsers/individual_event_detail.py
new file mode 100644
index 0000000..58e55a3
--- /dev/null
+++ b/gedcom/subparsers/individual_event_detail.py
@@ -0,0 +1,45 @@
+# -*- coding: utf-8 -*-
+
+# Python GEDCOM Parser
+#
+# Copyright (C) 2020 Christopher Horn (cdhorn at embarqmail dot com)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Further information about the license: http://www.gnu.org/licenses/gpl-2.0.html
+
+"""
+Substructure parser for a `INDIVIDUAL_EVENT_DETAIL` emdedded record.
+
+This is referenced as part of a larger structure so there is no anchor tag.
+"""
+
+import gedcom.tags as tags
+from gedcom.element.element import Element
+from gedcom.subparsers.event_detail import event_detail
+
+
+def individual_event_detail(element: Element) -> dict:
+ """Parses and extracts a `INDIVIDUAL_EVENT_DETAIL` structure.
+
+ The `element` should be the parent that contains it.
+ """
+ record = event_detail(element)
+ record['age'] = ''
+ for child in element.get_child_elements():
+ if child.get_tag() == tags.GEDCOM_TAG_AGE:
+ record['age'] = child.get_value()
+
+ return record
diff --git a/gedcom/subparsers/individual_event_structure.py b/gedcom/subparsers/individual_event_structure.py
new file mode 100644
index 0000000..5304a61
--- /dev/null
+++ b/gedcom/subparsers/individual_event_structure.py
@@ -0,0 +1,110 @@
+# -*- coding: utf-8 -*-
+
+# Python GEDCOM Parser
+#
+# Copyright (C) 2020 Christopher Horn (cdhorn at embarqmail dot com)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Further information about the license: http://www.gnu.org/licenses/gpl-2.0.html
+
+"""
+Substructure parser for a `INDIVIDUAL_EVENT_STRUCTURE` embedded record.
+
+This is referenced as part of a larger structure so there is no anchor tag.
+"""
+
+from typing import List
+
+import gedcom.tags as tags
+from gedcom.element.element import Element
+from gedcom.subparsers.individual_event_detail import individual_event_detail
+
+EVENT_TAGS = {
+ tags.GEDCOM_TAG_DEATH: 'death',
+ tags.GEDCOM_TAG_BURIAL: 'burial',
+ tags.GEDCOM_TAG_CREMATION: 'cremation',
+ tags.GEDCOM_TAG_BAPTISM: 'baptism',
+ tags.GEDCOM_TAG_BAR_MITZVAH: 'bar_mitzvah',
+ tags.GEDCOM_TAG_BAS_MITZVAH: 'bas_mitzvah',
+ tags.GEDCOM_TAG_BLESSING: 'blessing',
+ tags.GEDCOM_TAG_ADULT_CHRISTENING: 'adult_christening',
+ tags.GEDCOM_TAG_CONFIRMATION: 'confirmation',
+ tags.GEDCOM_TAG_FIRST_COMMUNION: 'first_communion',
+ tags.GEDCOM_TAG_ORDINATION: 'ordination',
+ tags.GEDCOM_TAG_NATURALIZATION: 'naturalization',
+ tags.GEDCOM_TAG_EMIGRATION: 'emmigration',
+ tags.GEDCOM_TAG_IMMIGRATION: 'immigration',
+ tags.GEDCOM_TAG_CENSUS: 'census',
+ tags.GEDCOM_TAG_PROBATE: 'probate',
+ tags.GEDCOM_TAG_WILL: 'will',
+ tags.GEDCOM_TAG_GRADUATION: 'graduation',
+ tags.GEDCOM_TAG_RETIREMENT: 'retirement',
+ tags.GEDCOM_TAG_EVENT: 'event',
+ tags.GEDCOM_PROGRAM_DEFINED_TAG_DEGREE: 'degree',
+ tags.GEDCOM_PROGRAM_DEFINED_TAG_FUNERAL: 'funeral',
+ tags.GEDCOM_PROGRAM_DEFINED_TAG_MEDICAL: 'medical',
+ tags.GEDCOM_PROGRAM_DEFINED_TAG_MILITARY: 'military'
+}
+
+BIRTH_EVENT_TAGS = {
+ tags.GEDCOM_TAG_BIRTH: 'birth',
+ tags.GEDCOM_TAG_CHRISTENING: 'christening'
+}
+
+
+def individual_event_structure(element: Element) -> List[dict]:
+ """Parses and extracts a `INDIVIDUAL_EVENT_STRUCTURE` structure.
+
+ The `element` should be the parent that contains it.
+ """
+ records = []
+ for child in element.get_child_elements():
+ if child.get_tag() in BIRTH_EVENT_TAGS:
+ record = individual_event_detail(child)
+ record['tag'] = child.get_tag()
+ record['event'] = BIRTH_EVENT_TAGS[child.get_tag()]
+ record['description'] = child.get_multi_line_value()
+ record['family'] = ''
+ for gchild in child.get_child_elements():
+ if gchild.get_tag() == tags.GEDCOM_TAG_FAMILY_CHILD:
+ record['family'] = gchild.get_value()
+ records.append(record)
+ continue
+
+ if child.get_tag() in EVENT_TAGS:
+ record = individual_event_detail(child)
+ record['tag'] = child.get_tag()
+ record['event'] = EVENT_TAGS[child.get_tag()]
+ record['description'] = child.get_multi_line_value()
+ records.append(record)
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_ADOPTION:
+ record = individual_event_detail(child)
+ record['tag'] = child.get_tag()
+ record['event'] = 'adoption'
+ record['description'] = child.get_multi_line_value()
+ record['family'] = ''
+ record['parent'] = ''
+ for gchild in child.get_child_elements():
+ if gchild.get_tag() == tags.GEDCOM_TAG_FAMILY_CHILD:
+ record['family'] = gchild.get_value()
+ for ggchild in gchild.get_child_elements():
+ if ggchild.get_tag() == tags.GEDCOM_TAG_ADOPTION:
+ record['parent'] = ggchild.get_value()
+ records.append(record)
+
+ return records
diff --git a/gedcom/subparsers/lds_individual_ordinance.py b/gedcom/subparsers/lds_individual_ordinance.py
new file mode 100644
index 0000000..2588558
--- /dev/null
+++ b/gedcom/subparsers/lds_individual_ordinance.py
@@ -0,0 +1,95 @@
+# -*- coding: utf-8 -*-
+
+# Python GEDCOM Parser
+#
+# Copyright (C) 2020 Christopher Horn (cdhorn at embarqmail dot com)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Further information about the license: http://www.gnu.org/licenses/gpl-2.0.html
+
+"""
+Substructure parser for a `LDS_INDIVIDUAL_ORDINANCE` embedded record.
+
+This is referenced as part of a larger structure so there is no anchor tag.
+"""
+
+from typing import List
+
+import gedcom.tags as tags
+from gedcom.element.element import Element
+from gedcom.subparsers.note_structure import note_structure
+from gedcom.subparsers.source_citation import source_citation
+
+ORDINANCE_TAGS = {
+ tags.GEDCOM_TAG_BAPTISM_LDS: 'lds_baptism',
+ tags.GEDCOM_TAG_CONFIRMATION_L: 'lds_confirmation',
+ tags.GEDCOM_TAG_ENDOWMENT: 'lds_endowment',
+ tags.GEDCOM_TAG_SEALING_CHILD: 'lds_sealing_child'
+}
+
+ORDINANCE_ATTRIBUTE_TAGS = {
+ tags.GEDCOM_TAG_DATE: 'date',
+ tags.GEDCOM_TAG_TEMPLE: 'temple',
+ tags.GEDCOM_TAG_PLACE: 'place',
+ tags.GEDCOM_TAG_FAMILY_CHILD: 'key_to_family'
+}
+
+
+def lds_individual_ordinance(element: Element) -> List[dict]:
+ """Parses and extracts a `LDS_INDIVIDUAL_ORDINANCE` structure.
+
+ The `element` should be the parent that contains it.
+ """
+ records = []
+ for child in element.get_child_elements():
+ if child.get_tag() in ORDINANCE_TAGS:
+ record = {
+ 'date': '',
+ 'temple': '',
+ 'place': '',
+ 'status': '',
+ 'status_change': '',
+ 'notes': [],
+ 'citations': [],
+ 'tag': child.get_tag(),
+ 'event': ORDINANCE_TAGS[child.get_tag()]
+ }
+ if child.get_tag() == tags.GEDCOM_TAG_SEALING_CHILD:
+ record.update({'key_to_family': ''})
+ for gchild in child.get_child_elements():
+ if gchild.get_tag() in ORDINANCE_ATTRIBUTE_TAGS:
+ record[ORDINANCE_ATTRIBUTE_TAGS[gchild.get_tag()]] = gchild.get_value()
+ continue
+
+ if gchild.get_tag() == tags.GEDCOM_TAG_STATUS:
+ record['status'] = gchild.get_value()
+ for ggchild in gchild.get_child_elements():
+ if ggchild.get_tag() == tags.GEDCOM_TAG_DATE:
+ record['status_change'] = ggchild.get_value()
+ continue
+
+ if gchild.get_tag() == tags.GEDCOM_TAG_NOTE:
+ record['notes'].append(note_structure(child))
+ continue
+
+ if gchild.get_tag() == tags.GEDCOM_TAG_SOURCE:
+ record['citations'].append(source_citation(child))
+ continue
+
+ records.append(record)
+ continue
+
+ return records
diff --git a/gedcom/subparsers/lds_spouse_sealing.py b/gedcom/subparsers/lds_spouse_sealing.py
new file mode 100644
index 0000000..cdc4545
--- /dev/null
+++ b/gedcom/subparsers/lds_spouse_sealing.py
@@ -0,0 +1,86 @@
+# -*- coding: utf-8 -*-
+
+# Python GEDCOM Parser
+#
+# Copyright (C) 2020 Christopher Horn (cdhorn at embarqmail dot com)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Further information about the license: http://www.gnu.org/licenses/gpl-2.0.html
+
+"""
+Substructure parser for a `LDS_SPOUSE_SEALING` embedded record.
+
+This is referenced as part of a larger structure so there is no anchor tag.
+"""
+
+from typing import List
+
+import gedcom.tags as tags
+from gedcom.element.element import Element
+from gedcom.subparsers.note_structure import note_structure
+from gedcom.subparsers.source_citation import source_citation
+
+SEALING_TAGS = {
+ tags.GEDCOM_TAG_DATE: 'date',
+ tags.GEDCOM_TAG_TEMPLE: 'temple',
+ tags.GEDCOM_TAG_PLACE: 'place',
+ tags.GEDCOM_TAG_FAMILY_CHILD: 'key_to_family'
+}
+
+
+def lds_spouse_sealing(element: Element) -> List[dict]:
+ """Parses and extracts a `LDS_SPOUSE_SEALING` structure.
+
+ The `element` should be the parent that contains it.
+ """
+ records = []
+ for child in element.get_child_elements():
+ if child.get_tag() == tags.GEDCOM_TAG_SEALING_SPOUSE:
+ record = {
+ 'date': '',
+ 'temple': '',
+ 'place': '',
+ 'status': '',
+ 'status_change': '',
+ 'notes': [],
+ 'citations': [],
+ 'tag': tags.GEDCOM_TAG_SEALING_SPOUSE,
+ 'event': 'lds_spouse_sealing'
+ }
+ for gchild in child.get_child_elements():
+ if gchild.get_tag() in SEALING_TAGS:
+ record[SEALING_TAGS[gchild.get_tag()]] = gchild.get_value()
+ continue
+
+ if gchild.get_tag() == tags.GEDCOM_TAG_STATUS:
+ record['status'] = gchild.get_value()
+ for ggchild in gchild.get_child_elements():
+ if ggchild.get_tag() == tags.GEDCOM_TAG_DATE:
+ record['status_change'] = ggchild.get_value()
+ continue
+
+ if gchild.get_tag() == tags.GEDCOM_TAG_NOTE:
+ record['notes'].append(note_structure(child))
+ continue
+
+ if gchild.get_tag() == tags.GEDCOM_TAG_SOURCE:
+ record['citations'].append(source_citation(child))
+ continue
+
+ records.append(record)
+ continue
+
+ return records
diff --git a/gedcom/subparsers/multimedia_link.py b/gedcom/subparsers/multimedia_link.py
new file mode 100644
index 0000000..3e0bc3f
--- /dev/null
+++ b/gedcom/subparsers/multimedia_link.py
@@ -0,0 +1,75 @@
+# -*- coding: utf-8 -*-
+
+# Python GEDCOM Parser
+#
+# Copyright (C) 2020 Christopher Horn (cdhorn at embarqmail dot com)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Further information about the license: http://www.gnu.org/licenses/gpl-2.0.html
+
+"""
+Substructure parser for a `MULTIMEDIA_LINK` record.
+
+This is anchored by the `gedcom.tags.GEDCOM_TAG_OBJECT` tag.
+"""
+
+import gedcom.tags as tags
+from gedcom.element.element import Element
+
+MEDIA_TAGS = {
+ tags.GEDCOM_TAG_FILE: 'file',
+ tags.GEDCOM_TAG_FORMAT: 'format',
+ tags.GEDCOM_TAG_MEDIA: 'type',
+ tags.GEDCOM_TAG_TITLE: 'title',
+ tags.GEDCOM_PROGRAM_DEFINED_TAG_PHOTO: 'preferred',
+ tags.GEDCOM_PROGRAM_DEFINED_TAG_PRIMARY: 'preferred'
+}
+
+
+def multimedia_link(element: Element) -> dict:
+ """Parse and extract a `MULTIMEDIA_LINK` structure.
+
+ The `element` should contain the `gedcom.tags.GEDCOM_TAG_OBJECT` tag.
+ """
+ record = {
+ 'key_to_object': element.get_value(),
+ 'file': '',
+ 'format': '',
+ 'type': '',
+ 'title': '',
+ 'preferred': ''
+ }
+ if record['key_to_object'] not in [None, '']:
+ if '@' in record['key_to_object']:
+ return record
+
+ record['key_to_object'] = ''
+ for child in element.get_child_elements():
+ if child.get_tag() == tags.GEDCOM_TAG_FILE:
+ record['file'] = child.get_value()
+ for gchild in child.get_child_elements():
+ if gchild.get_tag() == tags.GEDCOM_TAG_FORMAT:
+ record['format'] = gchild.get_value()
+ for ggchild in gchild.get_child_elements():
+ if ggchild.get_tag() == tags.GEDCOM_TAG_MEDIA:
+ record['type'] = ggchild.get_value()
+ continue
+ continue
+
+ if child.get_tag() in MEDIA_TAGS:
+ record[MEDIA_TAGS[child.get_tag()]] = child.get_value()
+
+ return record
diff --git a/gedcom/subparsers/note_structure.py b/gedcom/subparsers/note_structure.py
new file mode 100644
index 0000000..45f1c52
--- /dev/null
+++ b/gedcom/subparsers/note_structure.py
@@ -0,0 +1,47 @@
+# -*- coding: utf-8 -*-
+
+# Python GEDCOM Parser
+#
+# Copyright (C) 2020 Christopher Horn (cdhorn at embarqmail dot com)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Further information about the license: http://www.gnu.org/licenses/gpl-2.0.html
+
+"""
+Substructure parser for a `NOTE_STRUCTURE` record.
+
+This is anchored by the `gedcom.tags.GEDCOM_TAG_NOTE` tag.
+"""
+
+from gedcom.element.element import Element
+
+
+def note_structure(element: Element) -> dict:
+ """Parse and extract a `NOTE_STRUCTURE` structure.
+
+ The `element` should contain the `gedcom.tags.GEDCOM_TAG_NOTE` tag.
+ """
+ record = {
+ 'key_to_note': element.get_value(),
+ 'note': ''
+ }
+ if record['key_to_note'] not in [None, '']:
+ if '@' in record['key_to_note']:
+ return record
+ record['key_to_note'] = ''
+ record['note'] = element.get_multi_line_value()
+
+ return record
diff --git a/gedcom/subparsers/personal_name_pieces.py b/gedcom/subparsers/personal_name_pieces.py
new file mode 100644
index 0000000..d7c78e6
--- /dev/null
+++ b/gedcom/subparsers/personal_name_pieces.py
@@ -0,0 +1,74 @@
+# -*- coding: utf-8 -*-
+
+# Python GEDCOM Parser
+#
+# Copyright (C) 2020 Christopher Horn (cdhorn at embarqmail dot com)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Further information about the license: http://www.gnu.org/licenses/gpl-2.0.html
+
+"""
+Substructure parser for a `PERSONAL_NAME_PIECES` embedded record.
+
+This is referenced as part of a larger structure so there is no anchor tag.
+"""
+
+import gedcom.tags as tags
+from gedcom.element.element import Element
+from gedcom.subparsers.note_structure import note_structure
+from gedcom.subparsers.source_citation import source_citation
+
+NAME_TAGS = {
+ tags.GEDCOM_TAG_NAME_PREFIX: 'prefix',
+ tags.GEDCOM_TAG_GIVEN_NAME: 'given',
+ tags.GEDCOM_TAG_NICKNAME: 'nick',
+ tags.GEDCOM_TAG_SURN_PREFIX: 'surname_prefix',
+ tags.GEDCOM_TAG_SURNAME: 'surname',
+ tags.GEDCOM_TAG_NAME_SUFFIX: 'suffix',
+ tags.GEDCOM_PROGRAM_DEFINED_TAG_RUFNAME: 'rufname'
+}
+
+
+def personal_name_pieces(element: Element) -> dict:
+ """Parse and extract a `PERSONAL_NAME_PIECES` structure.
+
+ The `element` should be the parent that contains it.
+ """
+ record = {
+ 'prefix': '',
+ 'given': '',
+ 'nick': '',
+ 'surname_prefix': '',
+ 'surname': '',
+ 'suffix': '',
+ 'rufname': '',
+ 'notes': [],
+ 'citations': []
+ }
+ for child in element.get_child_elements():
+ if child.get_tag() in NAME_TAGS:
+ record[NAME_TAGS[child.get_tag()]] = child.get_value()
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_NOTE:
+ record['notes'].append(note_structure(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_SOURCE:
+ record['citations'].append(source_citation(child))
+ continue
+
+ return record
diff --git a/gedcom/subparsers/personal_name_structure.py b/gedcom/subparsers/personal_name_structure.py
new file mode 100644
index 0000000..c20fd5b
--- /dev/null
+++ b/gedcom/subparsers/personal_name_structure.py
@@ -0,0 +1,75 @@
+# -*- coding: utf-8 -*-
+
+# Python GEDCOM Parser
+#
+# Copyright (C) 2020 Christopher Horn (cdhorn at embarqmail dot com)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Further information about the license: http://www.gnu.org/licenses/gpl-2.0.html
+
+"""
+Substructure parser for a `PERSONAL_NAME_STRUCTURE` record.
+
+This is anchored by the `gedcom.tags.GEDCOM_TAG_NAME` tag.
+"""
+
+import gedcom.tags as tags
+from gedcom.element.element import Element
+from gedcom.subparsers.personal_name_pieces import personal_name_pieces
+
+
+def extract_name(element: Element) -> dict:
+ """Parse and extract a `NAME` for a `PERSONAL_NAME_STRUCTURE` structure.
+
+ The `element` should contain one of the name tags:
+
+ `gedcom.tags.GEDCOM_TAG_NAME`
+
+ `gedcom.tags.GEDCOM_TAG_PHONETIC`
+
+ `gedcom.tags.GEDCOM_TAG_ROMANIZED`
+ """
+ record = {
+ 'name': '',
+ 'type': '',
+ 'pieces': {}
+ }
+ record['name'] = element.get_value()
+ record['pieces'] = personal_name_pieces(element)
+ for child in element.get_child_elements():
+ if child.get_tag() == tags.GEDCOM_TAG_TYPE:
+ record['type'] = child.get_value()
+ return record
+
+
+def personal_name_structure(element: Element) -> dict:
+ """Parse and extract a `PERSONAL_NAME_STRUCTURE` structure.
+
+ The `element` should contain the `gedcom.tags.GEDCOM_TAG_NAME` tag.
+ """
+ record = extract_name(element)
+ record['phonetic'] = []
+ record['romanized'] = []
+ for child in element.get_child_elements():
+ if child.get_tag() == tags.GEDCOM_TAG_PHONETIC:
+ record['phonetic'].append(extract_name(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_ROMANIZED:
+ record['romanized'].append(extract_name(child))
+ continue
+
+ return record
diff --git a/gedcom/subparsers/place_structure.py b/gedcom/subparsers/place_structure.py
new file mode 100644
index 0000000..13ac917
--- /dev/null
+++ b/gedcom/subparsers/place_structure.py
@@ -0,0 +1,88 @@
+# -*- coding: utf-8 -*-
+
+# Python GEDCOM Parser
+#
+# Copyright (C) 2020 Christopher Horn (cdhorn at embarqmail dot com)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Further information about the license: http://www.gnu.org/licenses/gpl-2.0.html
+
+"""
+Substructure parser for a `PLACE_STRUCTURE` record.
+
+This is anchored by the `gedcom.tags.GEDCOM_TAG_PLACE` tag.
+"""
+
+import gedcom.tags as tags
+from gedcom.element.element import Element
+from gedcom.subparsers.note_structure import note_structure
+
+
+def place_structure(element: Element) -> dict:
+ """Parse and extract a `PLACE_STRUCTURE` structure.
+
+ The `element` should contain the `gedcom.tags.GEDCOM_TAG_PLACE` tag.
+ """
+ record = {
+ 'name': element.get_value(),
+ 'hierarchy': '',
+ 'phonetic': [],
+ 'romanized': [],
+ 'latitude': '',
+ 'longitude': '',
+ 'notes': []
+ }
+ for child in element.get_child_elements():
+ if child.get_tag() == tags.GEDCOM_TAG_FORMAT:
+ record['hierarchy'] = child.get_value()
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_NOTE:
+ record['notes'].append(note_structure(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_PHONETIC:
+ subrecord = {
+ 'name': child.get_value(),
+ 'type': ''
+ }
+ for gchild in child.get_child_elements():
+ if gchild.get_tag() == tags.GEDCOM_TAG_TYPE:
+ subrecord['type'] = gchild.get_value()
+ record['phonetic'].append(subrecord)
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_ROMANIZED:
+ subrecord = {
+ 'name': child.get_value(),
+ 'type': ''
+ }
+ for gchild in child.get_child_elements():
+ if gchild.get_tag() == tags.GEDCOM_TAG_TYPE:
+ subrecord['type'] = gchild.get_value()
+ record['romanized'].append(subrecord)
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_MAP:
+ for gchild in child.get_child_elements():
+ if gchild.get_tag() == tags.GEDCOM_TAG_LATITUDE:
+ record['latitude'] = gchild.get_value()
+ continue
+
+ if gchild.get_tag() == tags.GEDCOM_TAG_LONGITUDE:
+ record['longitude'] = gchild.get_value()
+
+ return record
diff --git a/gedcom/subparsers/source_citation.py b/gedcom/subparsers/source_citation.py
new file mode 100644
index 0000000..ef61f03
--- /dev/null
+++ b/gedcom/subparsers/source_citation.py
@@ -0,0 +1,97 @@
+# -*- coding: utf-8 -*-
+
+# Python GEDCOM Parser
+#
+# Copyright (C) 2020 Christopher Horn (cdhorn at embarqmail dot com)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Further information about the license: http://www.gnu.org/licenses/gpl-2.0.html
+
+"""
+Substructure parser for a `SOURCE_CITATION` record.
+
+This is anchored by the `gedcom.tags.GEDCOM_TAG_SOURCE` tag.
+"""
+
+import gedcom.tags as tags
+from gedcom.element.element import Element
+from gedcom.subparsers.multimedia_link import multimedia_link
+from gedcom.subparsers.note_structure import note_structure
+
+CITATION_TAGS = {
+ tags.GEDCOM_TAG_PAGE: 'page',
+ tags.GEDCOM_TAG_DATE: 'date',
+ tags.GEDCOM_TAG_QUALITY_OF_DATA: 'quality',
+ tags.GEDCOM_PROGRAM_DEFINED_TAG_APID: 'apid'
+}
+
+
+def source_citation(element: Element) -> dict:
+ """Parse and extract a `SOURCE_CITATION` structure.
+
+ The `element` should contain the `gedcom.tags.GEDCOM_TAG_SOURCE` tag.
+ """
+ record = {
+ 'key_to_source': element.get_value(),
+ 'source': '',
+ 'page': '',
+ 'event': '',
+ 'role': '',
+ 'date': '',
+ 'text': '',
+ 'media': [],
+ 'notes': [],
+ 'quality': '',
+ 'apid': ''
+ }
+ if record['key_to_source'] not in [None, '']:
+ if '@' not in record['key_to_source']:
+ record['key_to_source'] = ''
+ record['source'] = element.get_multi_line_value()
+
+ for child in element.get_child_elements():
+ if child.get_tag() in CITATION_TAGS:
+ record[CITATION_TAGS[child.get_tag()]] = child.get_value()
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_EVENT:
+ record['event'] = child.get_value()
+ for gchild in child.get_child_elements():
+ if gchild.get_tag() == tags.GEDCOM_TAG_ROLE:
+ record['role'] = gchild.get_value()
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_DATA:
+ for gchild in child.get_child_elements():
+ if gchild.get_tag() == tags.GEDCOM_TAG_DATE:
+ record['date'] = gchild.get_value()
+ continue
+ if gchild.get_tag() == tags.GEDCOM_TAG_TEXT:
+ record['text'] = gchild.get_multi_line_value()
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_OBJECT:
+ record['media'].append(multimedia_link(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_NOTE:
+ record['notes'].append(note_structure(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_TEXT:
+ record['text'] = child.get_multi_line_value()
+
+ return record
diff --git a/gedcom/subparsers/source_repository_citation.py b/gedcom/subparsers/source_repository_citation.py
new file mode 100644
index 0000000..dc67f40
--- /dev/null
+++ b/gedcom/subparsers/source_repository_citation.py
@@ -0,0 +1,60 @@
+# -*- coding: utf-8 -*-
+
+# Python GEDCOM Parser
+#
+# Copyright (C) 2020 Christopher Horn (cdhorn at embarqmail dot com)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Further information about the license: http://www.gnu.org/licenses/gpl-2.0.html
+
+"""
+Substructure parser for a `SOURCE_REPOSITORY_CITATION` record.
+
+This is anchored by the `gedcom.tags.GEDCOM_TAG_REPOSITORY` tag.
+"""
+
+import gedcom.tags as tags
+from gedcom.element.element import Element
+from gedcom.subparsers.note_structure import note_structure
+
+
+def source_repository_citation(element: Element) -> dict:
+ """Parse and extract a `SOURCE_REPOSITORY_CITATION` structure.
+
+ The `element` should contain the `gedcom.tags.GEDCOM_TAG_REPOSITORY` tag.
+ """
+ record = {
+ 'key_to_repository': element.get_value(),
+ 'call_number': '',
+ 'media_type': '',
+ 'notes': []
+ }
+ if record['key_to_repository'] not in [None, '']:
+ if '@' not in record['key_to_repository']:
+ record['key_to_repository'] = ''
+
+ for child in element.get_child_elements():
+ if child.get_tag() == tags.GEDCOM_TAG_NOTE:
+ record['notes'].append(note_structure(child))
+ continue
+
+ if child.get_tag() == tags.GEDCOM_TAG_CALL_NUMBER:
+ record['call_number'] = child.get_value()
+ for gchild in child.get_child_elements():
+ if gchild.get_tag() == tags.GEDCOM_TAG_MEDIA:
+ record['media_type'] = gchild.get_value()
+
+ return record
diff --git a/gedcom/subparsers/spouse_to_family_link.py b/gedcom/subparsers/spouse_to_family_link.py
new file mode 100644
index 0000000..3d2895e
--- /dev/null
+++ b/gedcom/subparsers/spouse_to_family_link.py
@@ -0,0 +1,47 @@
+# -*- coding: utf-8 -*-
+
+# Python GEDCOM Parser
+#
+# Copyright (C) 2020 Christopher Horn (cdhorn at embarqmail dot com)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Further information about the license: http://www.gnu.org/licenses/gpl-2.0.html
+
+"""
+Substructure parser for a `SPOUSE_TO_FAMILY_LINK` record.
+
+This is anchored by the `gedcom.tags.GEDCOM_TAG_FAMILY_SPOUSE` tag.
+"""
+
+import gedcom.tags as tags
+from gedcom.element.element import Element
+from gedcom.subparsers.note_structure import note_structure
+
+
+def spouse_to_family_link(element: Element) -> dict:
+ """Parse and extract a `SPOUSE_TO_FAMILY_LINK` structure.
+
+ The `element` should contain the `gedcom.tags.GEDCOM_TAG_FAMILY_SPOUSE` tag.
+ """
+ record = {
+ 'key_to_family': element.get_value(),
+ 'notes': []
+ }
+ for child in element.get_child_elements():
+ if child.get_tag() == tags.GEDCOM_TAG_NOTE:
+ record['notes'].append(note_structure(child))
+
+ return record
diff --git a/gedcom/subparsers/user_reference_number.py b/gedcom/subparsers/user_reference_number.py
new file mode 100644
index 0000000..a1e4d7c
--- /dev/null
+++ b/gedcom/subparsers/user_reference_number.py
@@ -0,0 +1,49 @@
+# -*- coding: utf-8 -*-
+
+# Python GEDCOM Parser
+#
+# Copyright (C) 2020 Christopher Horn (cdhorn at embarqmail dot com)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Further information about the license: http://www.gnu.org/licenses/gpl-2.0.html
+
+"""
+Parser for a `USER_REFERENCE_NUMBER` structure.
+
+This is anchored by the `gedcom.tags.GEDCOM_TAG_REFERENCE` tag.
+
+This is not a formally documented structure in the standard but it is
+a substructure that repeats itself in a number of record types.
+"""
+
+import gedcom.tags as tags
+from gedcom.element.element import Element
+
+
+def user_reference_number(element: Element) -> dict:
+ """Parse and extract a `USER_REFERENCE_NUMBER` structure.
+
+ The `element` should contain the `gedcom.tags.GEDCOM_TAG_REFERENCE` tag.
+ """
+ record = {
+ 'reference': element.get_value(),
+ 'type': ''
+ }
+ for child in element.get_child_elements():
+ if child.get_tag() == tags.GEDCOM_TAG_TYPE:
+ record['type'] = child.get_value()
+
+ return record
diff --git a/gedcom/tags.py b/gedcom/tags.py
index 9efa002..63c6e95 100644
--- a/gedcom/tags.py
+++ b/gedcom/tags.py
@@ -2,6 +2,7 @@
# Python GEDCOM Parser
#
+# Copyright (C) 2020 Christopher Horn (cdhorn at embarqmail dot com)
# Copyright (C) 2018 Damon Brodie (damon.brodie at gmail.com)
# Copyright (C) 2018-2019 Nicklas Reincke (contact at reynke.com)
# Copyright (C) 2016 Andreas Oberritter
@@ -26,63 +27,392 @@
# Further information about the license: http://www.gnu.org/licenses/gpl-2.0.html
"""
-GEDCOM tags.
+Module containing the standard GEDCOM tags and some of the most common program defined extensions.
"""
-GEDCOM_PROGRAM_DEFINED_TAG_MREL = "_MREL"
-"""Value: `_MREL`
+GEDCOM_PROGRAM_DEFINED_TAG_ADDRESSE = "_NAME"
+"""Value: `_NAME`
+
+Name of addresse in a `gedcom.tags.GEDCOM_TAG_ADDRESS` structure.
+
+5.5.1 GEDCOM-L Addendum."""
+
+GEDCOM_PROGRAM_DEFINED_TAG_ADMINISTRATIVE_ID = "_AIDN"
+"""Value: `_AIDN`
+
+Identifier for a location with the intention of an administrative authority,
+e.g. community identifier.
+
+5.5.1 GEDCOM-L Addendum."""
+
+GEDCOM_PROGRAM_DEFINED_TAG_APID = "_APID"
+"""Value: `_APID`
+
+Ancestry page identifier. For a citation, points to the page in a Ancestry
+database for the record supporting the citation. For a source record it
+points to the database as a whole.
-Relationship to a mother."""
+Ancestry.com Extension."""
+
+GEDCOM_PROGRAM_DEFINED_TAG_DCAUSE = "_DCAUSE"
+"""Value: `_DCAUSE`
+
+Cause of death."""
+
+GEDCOM_PROGRAM_DEFINED_TAG_DEGREE = "_DEG"
+"""Value: `_DEG`
+
+Degree or recognition of accomplishment received by an individual."""
+
+GEDCOM_PROGRAM_DEFINED_TAG_DEMOGRAPHIC_DATA = "_DMGD"
+"""Value: `_DMGD`
+
+A number of ojects, during an ascertainment, e.g. the count of households.
+
+5.5.1 GEDCOM-L Addendum."""
GEDCOM_PROGRAM_DEFINED_TAG_FREL = "_FREL"
"""Value: `_FREL`
-Relationship to a father."""
+Type of relationship between child and the father in a family."""
+
+GEDCOM_PROGRAM_DEFINED_TAG_FUNERAL = "_FUN"
+"""Value: `_FUN`
+
+Funeral for an individual."""
+
+GEDCOM_PROGRAM_DEFINED_TAG_GOVERNMENT = "_GOV"
+"""Value: `_GOV`
+
+The official government id of the object in the Historical Place Register /
+Historic Gazeteer.
+
+5.5.1 GEDCOM-L Addendum."""
+
+GEDCOM_PROGRAM_DEFINED_TAG_GOVERNMENT_TYPE = "_GOVTYPE"
+"""Value: `_GOVTYPE`
+
+An integer positive number as defined in the GOV system.
+See http://gov.genealogy.net.net/type/list.
+
+5.5.1 GEDCOM-L Addendum."""
+
+GEDCOM_PROGRAM_DEFINED_TAG_HOME_PERSON = "_HME"
+"""Value: `_HME`
+
+Home person in the tree."""
+
+GEDCOM_PROGRAM_DEFINED_TAG_LOCATION = "_LOC"
+"""Value: `_LOC`
+
+Location data record.
+
+5.5.1 GEDCOM-L Addendum."""
+
+GEDCOM_PROGRAM_DEFINED_TAG_MAIDENHEAD = "_MAIDENHEAD"
+"""Value: `_MAIDENHEAD`
+
+The maidenhead code.
+
+5.5.1 GEDCOM-L Addendum."""
+
+GEDCOM_PROGRAM_DEFINED_TAG_MEDICAL = "_MDCL"
+"""Value: `_MDCL`
+
+Medical information about an individual."""
+
+GEDCOM_PROGRAM_DEFINED_TAG_MILITARY = "_MILT"
+"""Value: `_MILT`
+
+A military related event in the individuals life."""
+
+GEDCOM_PROGRAM_DEFINED_TAG_MREL = "_MREL"
+"""Value: `_MREL`
+
+Type of relationship between child and the mother in a family."""
+
+GEDCOM_PROGRAM_DEFINED_TAG_PHOTO = "_PHOTO"
+"""Value: `_PHOTO`
+
+Used by some programs to identify the primary multimedia object for an
+individual, the same as `gedcom.tags.GEDCOM_PROGRAM_DEFINED_TAG_PRIMARY`."""
+
+GEDCOM_PROGRAM_DEFINED_TAG_POSTAL_CODE = "_POST"
+"""Value: `_POST`
+
+The official zip code, called ADDRESS_POSTAL_CODE in the standard.
+
+5.5.1 GEDCOM-L Addendum."""
+
+GEDCOM_PROGRAM_DEFINED_TAG_PREFERRED = "_PREF"
+"""Value: `_PREF`
+
+Indicates a preferred spouse, child or parents."""
+
+GEDCOM_PROGRAM_DEFINED_TAG_PRIMARY = "_PRIM"
+"""Value: `_PRIM`
+
+Primary multimedia object for an individual."""
+
+GEDCOM_PROGRAM_DEFINED_TAG_SCHEMA = "_SCHEMA"
+"""Value: `_SCHEMA`
+
+Schema substructure extension to describe user defined tags.
+
+5.5.1 GEDCOM-L Addendum."""
+
+GEDCOM_PROGRAM_DEFINED_TAG_RUFNAME = "_RUFNAME"
+"""Value: `_RUFNAME`
+
+An official given name of a German individual used in legal documents.
+
+5.5.1 GEDCOM-L Addendum."""
+
+GEDCOM_PROGRAM_DEFINED_TAG_UUID = "_UID"
+"""Value: `_UID`
+
+Universal identification number.
+
+5.5.1 GEDCOM-L Addendum."""
+
+GEDCOM_TAG_ABBREVIATION = "ABBR"
+"""Value: `ABBR`
+
+A short name of a title, description, or name."""
+
+GEDCOM_TAG_ADDRESS = "ADDR"
+"""Value: `ADDR`
+
+The contemporary place, usually required for postal purposes, of an individual,
+a submitter of information, a repository, a business, a school, or a company."""
+
+GEDCOM_TAG_ADDRESS1 = "ADR1"
+"""Value: `ADR1`
+
+The first line of an address."""
+
+GEDCOM_TAG_ADDRESS2 = "ADR2"
+"""Value: `ADR2`
+
+The second line of an address."""
+
+GEDCOM_TAG_ADDRESS3 = "ADR3"
+"""Value: `ADR3`
+
+The third line of an address."""
+
+GEDCOM_TAG_ADOPTION = "ADOP"
+"""Value: `ADOP`
+
+Pertaining to creation of a child-parent relationship that does not exist
+biologically."""
+
+GEDCOM_TAG_AFN = "AFN"
+"""Value: `AFN`
+
+Ancestral File Number, a unique permanent record file number of an individual
+record stored in Ancestral File."""
+
+GEDCOM_TAG_AGE = "AGE"
+"""Value: `AGE`
+
+The age of the individual at the time an event occurred, or the age listed in
+the document."""
+
+GEDCOM_TAG_AGENCY = "AGNC"
+"""Value: `AGNC`
+
+The institution or individual having authority and/or responsibility to manage
+or govern."""
+
+GEDCOM_TAG_ALIAS = "ALIA"
+"""Value: `ALIA`
+
+An indicator to link different record descriptions of a person who may be the
+same person."""
+
+GEDCOM_TAG_ANCESTORS = "ANCE"
+"""Value: `ANCE`
+
+Pertaining to forbearers of an individual."""
+
+GEDCOM_TAG_ANCES_INTEREST = "ANCI"
+"""Value: `ANCI`
+
+Indicates an interest in additional research for ancestors of this individual.
+(See also `gedcom.tags.GEDCOM_TAG_DESCENDANTS_INT`)"""
+
+GEDCOM_TAG_ANNULMENT = "ANUL"
+"""Value: `ANUL`
+
+Declaring a marriage void from the beginning (never existed)."""
+
+GEDCOM_TAG_ASSOCIATES = "ASSO"
+"""Value: `ASSO`
+
+An indicator to link friends, neighbors, relatives, or associates of an
+individual."""
+
+GEDCOM_TAG_AUTHOR = "AUTH"
+"""Value: `AUTH`
+
+The name of the individual who created or compiled information."""
+
+GEDCOM_TAG_BAPTISM_LDS = "BAPL"
+"""Value: `BAPL`
+
+The event of baptism performed at age eight or later by priesthood authority
+of the LDS Church. (See also `gedcom.tags.GEDCOM_TAG_BAPTISM`)"""
+
+GEDCOM_TAG_BAPTISM = "BAPM"
+"""Value: `BAPM`
+
+The event of baptism (not LDS), performed in infancy or later."""
+
+GEDCOM_TAG_BAR_MITZVAH = "BARM"
+"""Value: `BARM`
+
+The ceremonial event held when a Jewish boy reaches age 13."""
+
+GEDCOM_TAG_BAS_MITZVAH = "BASM"
+"""Value: `BASM`
+
+The ceremonial event held when a Jewish girl reaches age 13, also known as
+Bat Mitzvah."""
GEDCOM_TAG_BIRTH = "BIRT"
"""Value: `BIRT`
The event of entering into life."""
+GEDCOM_TAG_BLESSING = "BLES"
+"""Value: `BLES`
+
+A religious event of bestowing divine care or intercession. Sometimes given
+in connection with a naming ceremony."""
+
GEDCOM_TAG_BURIAL = "BURI"
"""Value: `BURI`
The event of the proper disposing of the mortal remains of a deceased person."""
+GEDCOM_TAG_CALL_NUMBER = "CALN"
+"""Value: `CALN`
+
+The number used by a repository to identify the specific items in its
+collections."""
+
+GEDCOM_TAG_CASTE = "CAST"
+"""Value: `CAST`
+
+The name of an individual's rank or status in society, based on racial or
+religious differences, or differences in wealth, inherited rank, profession,
+occupation, etc."""
+
+GEDCOM_TAG_CAUSE = "CAUSE"
+"""Value: `CAUS`
+
+A description of the cause of the associated event or fact, such as the cause
+of death."""
+
GEDCOM_TAG_CENSUS = "CENS"
"""Value: `CENS`.
-The event of the periodic count of the population for a designated locality, such as a national or state Census."""
+The event of the periodic count of the population for a designated locality,
+such as a national or state Census."""
GEDCOM_TAG_CHANGE = "CHAN"
"""Value: `CHAN`
Indicates a change, correction, or modification. Typically used in connection
-with a `gedcom.tags.GEDCOM_TAG_DATE` to specify when a change in information occurred."""
+with a `gedcom.tags.GEDCOM_TAG_DATE` to specify when a change in information
+occurred."""
+
+GEDCOM_TAG_CHARACTER = "CHAR"
+"""Value: `CHAR`
+
+An indicator of the character set used in writing this automated information."""
GEDCOM_TAG_CHILD = "CHIL"
"""Value: `CHIL`
The natural, adopted, or sealed (LDS) child of a father and a mother."""
+GEDCOM_TAG_CHRISTENING = "CHR"
+"""Value: `CHR`
+
+The religious event (not LDS) of baptizing and/or naming a child."""
+
+GEDCOM_TAG_ADULT_CHRISTENING = "CHRA"
+"""Value: `CHRA`
+
+The religious event (not LDS) of baptizing and/or naming an adult person."""
+
+GEDCOM_TAG_CITY = "CITY"
+"""Value: `CITY`
+
+A lower level jurisdictional unit. Normally an incorporated municipal unit."""
+
GEDCOM_TAG_CONCATENATION = "CONC"
"""Value: `CONC`
-An indicator that additional data belongs to the superior value. The information from the `CONC` value is to
-be connected to the value of the superior preceding line without a space and without a carriage return and/or
-new line character. Values that are split for a `CONC` tag must always be split at a non-space. If the value is
-split on a space the space will be lost when concatenation takes place. This is because of the treatment that
-spaces get as a GEDCOM delimiter, many GEDCOM values are trimmed of trailing spaces and some systems look for
-the first non-space starting after the tag to determine the beginning of the value."""
+An indicator that additional data belongs to the superior value. The information
+from the `CONC` value is to be connected to the value of the superior preceding
+line without a space and without a carriage return and/or new line character.
+Values that are split for a `CONC` tag must always be split at a non-space. If
+the value is split on a space the space will be lost when concatenation takes
+place. This is because of the treatment that spaces get as a GEDCOM delimiter,
+many GEDCOM values are trimmed of trailing spaces and some systems look for
+the first non-space starting after the tag to determine the beginning of the
+value."""
+
+GEDCOM_TAG_CONFIRMATION = "CONF"
+"""Value: `CONF`
+
+The religious event (not LDS) of conferring the gift of the Holy Ghost and,
+among protestants, full church membership."""
+
+GEDCOM_TAG_CONFIRMATION_L = "CONL"
+"""Value: `CONL`
+
+The religious event by which a person receives membership in the LDS Church."""
GEDCOM_TAG_CONTINUED = "CONT"
"""Value: `CONT`
-An indicator that additional data belongs to the superior value. The information from the `CONT` value is to be
-connected to the value of the superior preceding line with a carriage return and/or new line character.
-Leading spaces could be important to the formatting of the resultant text. When importing values from `CONT` lines
-the reader should assume only one delimiter character following the `CONT` tag. Assume that the rest of the leading
-spaces are to be a part of the value."""
+An indicator that additional data belongs to the superior value. The information
+from the `CONT` value is to be connected to the value of the superior preceding
+line with a carriage return and/or new line character. Leading spaces could be
+important to the formatting of the resultant text. When importing values from
+`CONT` lines the reader should assume only one delimiter character following
+the `CONT` tag. Assume that the rest of the leading spaces are to be a part
+of the value."""
+
+GEDCOM_TAG_COPYRIGHT = "COPR"
+"""Value: `COPR`
+
+A statement that accompanies data to protect it from unlawful duplication
+and distribution."""
+
+GEDCOM_TAG_CORPORATE = "CORP"
+"""Value: `CORP`
+
+A name of an institution, agency, corporation, or company."""
+
+GEDCOM_TAG_CREMATION = "CREM"
+"""Value: `CREM`
+
+Disposal of the remains of a person's body by fire."""
+
+GEDCOM_TAG_COUNTRY = "CTRY"
+"""Value: `CTRY`
+
+The name or code of a country."""
+
+GEDCOM_TAG_DATA = "DATA"
+"""Value: `DATA`
+
+Pertaining to stored automation information."""
GEDCOM_TAG_DATE = "DATE"
"""Value: `DATE`
@@ -94,90 +424,539 @@
The event when mortal life terminates."""
+GEDCOM_TAG_DESCENDANTS = "DESC"
+"""Value: `DESC`
+
+Pertaining to offspring of an individual."""
+
+GEDCOM_TAG_DESCENDANTS_INT = "DESI"
+"""Value: `DESI`
+
+Indicates an interest in research to identify additional descendants of this
+individual. (See also `gedcom.tags.GEDCOM_TAG_ANCES_INTEREST`)"""
+
+GEDCOM_TAG_DESTINATION = "DEST"
+"""Value: `DEST`
+
+A system receiving data."""
+
+GEDCOM_TAG_DIVORCE = "DIV"
+"""Value: `DIV`
+
+The event of disolving a marriage through civil action."""
+
+GEDCOM_TAG_DIVORCE_FILED = "DIVF"
+"""Value: `DIVF`
+
+An event of filing for a divorce by a spouse."""
+
+GEDCOM_TAG_PHY_DESCRIPTION = "DSCR"
+"""Value: `DSCR`
+
+The physical characteristics of a person, place, or thing."""
+
+GEDCOM_TAG_EDUCATION = "EDUC"
+"""Value: `EDUC`
+
+Indicator of a level of education attained."""
+
+GEDCOM_TAG_EMAIL = "EMAIL"
+"""Value: `EMAIL`
+
+An electronic address that can be used for contact such as an email address."""
+
+GEDCOM_TAG_EMIGRATION = "EMIG"
+"""Value: `EMIG`
+
+An event of leaving one's homeland with the intent of residing elsewhere."""
+
+GEDCOM_TAG_ENDOWMENT = "ENDL"
+"""Value: `ENDL`
+
+A religious event where an endowment ordinance for an individual was performed
+by priesthood authority in an LDS temple."""
+
+GEDCOM_TAG_ENGAGEMENT = "ENGA"
+"""Value: `ENGA`
+
+An event of recording or announcing an agreement between two people to become
+married."""
+
+GEDCOM_TAG_EVENT = "EVEN"
+"""Value: `EVEN`
+
+A noteworthy happening related to an individual, a group, or an organization."""
+
+GEDCOM_TAG_FACT = "FACT"
+"""Value: `FACT`
+
+Pertaining to a noteworthy attribute or fact concerning an individual, a group,
+or an organization. A `FACT` structure is usually qualified or classified by a
+subordinate use of the `gedcom.tags.GEDCOM_TAG_TYPE` tag."""
+
GEDCOM_TAG_FAMILY = "FAM"
"""Value: `FAM`.
-Identifies a legal, common law, or other customary relationship of man and woman and their children,
-if any, or a family created by virtue of the birth of a child to its biological father and mother."""
+Identifies a legal, common law, or other customary relationship of man and woman
+and their children, if any, or a family created by virtue of the birth of a
+child to its biological father and mother."""
GEDCOM_TAG_FAMILY_CHILD = "FAMC"
"""Value: `FAMC`
Identifies the family in which an individual appears as a child."""
+GEDCOM_TAG_FAMILY_FILE = "FAMF"
+"""Value: `FAMF`
+
+Pertaining to, or the name of, a family file. Names stored in a file that are
+assigned to a family for doing temple ordinance work."""
+
GEDCOM_TAG_FAMILY_SPOUSE = "FAMS"
"""Value: `FAMS`
Identifies the family in which an individual appears as a spouse."""
+GEDCOM_TAG_FAX = "FAX"
+"""Value: `FAX`
+
+A FAX telephone number appropriate for sending data facsimiles."""
+
+GEDCOM_TAG_FIRST_COMMUNION = "FCOM"
+"""Value: `FCOM`
+
+A religious rite, the first act of sharing in the Lord's supper as part of
+church worship."""
+
GEDCOM_TAG_FILE = "FILE"
"""Value: `FILE`
-An information storage place that is ordered and arranged for preservation and reference."""
+An information storage place that is ordered and arranged for preservation and
+reference."""
+
+GEDCOM_TAG_PHONETIC = "FONE"
+"""Value: `FONE`
+
+A phonetic variation of a superior text string."""
+
+GEDCOM_TAG_FORMAT = "FORM"
+"""Value: `FORM`
+
+An assigned name given to a consistent format in which information can be
+conveyed."""
+
+GEDCOM_TAG_GEDCOM = "GEDC"
+"""Value: `GEDC`
+
+Information about the use of GEDCOM in a transmission."""
GEDCOM_TAG_GIVEN_NAME = "GIVN"
"""Value: `GIVN`
A given or earned name used for official identification of a person."""
+GEDCOM_TAG_GRADUATION = "GRAD"
+"""Value: `GRAD`
+
+An event of awarding educational diplomas or degrees to individuals."""
+
+GEDCOM_TAG_HEADER = "HEAD"
+"""Value: `HEAD`
+
+Identifies information pertaining to an entire GEDCOM transmission."""
+
GEDCOM_TAG_HUSBAND = "HUSB"
"""Value: `HUSB`
An individual in the family role of a married man or father."""
+GEDCOM_TAG_IDENT_NUMBER = "IDNO"
+"""Value: `IDNO`
+
+A number assigned to identify a person within some significant external system."""
+
+GEDCOM_TAG_IMMIGRATION = "IMMI"
+"""Value: `IMMI`
+
+An event of entering into a new locality witht he intent of residing there."""
+
GEDCOM_TAG_INDIVIDUAL = "INDI"
"""Value: `INDI`
A person."""
+GEDCOM_TAG_LANGUAGE = "LANG"
+"""Value: `LANG`
+
+The name of the language used in a communication or transmission of information."""
+
+GEDCOM_TAG_LATITUDE = "LATI"
+"""Value: `LATI`
+
+A value indicating a coordinate position on a line, plane, or space."""
+
+GEDCOM_TAG_LEGATEE = "LEGA"
+"""Value: `LEGA`
+
+A role of an individual acting as a person receiving a bequest or legal devise."""
+
+GEDCOM_TAG_LONGITUDE = "LONG"
+"""Value: `LONG`
+
+A value indicating a coordinate position on a line, plane, or space."""
+
+GEDCOM_TAG_MAP = "MAP"
+"""Value: `MAP`
+
+Pertains to a representation of measurements usually presented in a graphical
+form."""
+
+GEDCOM_TAG_MARRIAGE_BANN = "MARB"
+"""Value: `MARB`.
+
+An event of an official public notice given that two people intend to marry."""
+
+GEDCOM_TAG_MARR_CONTRACT = "MARC"
+"""Value: `MARC`.
+
+An event of recording a formal agreement of marriage, including the prenuptial
+agreement in which marriage partners reach agreement about the property rights
+of one or both, securing property to their children."""
+
+GEDCOM_TAG_MARR_LICENSE = "MARL"
+"""Value: `MARL`.
+
+An event of obtaining a legal license to marry."""
+
GEDCOM_TAG_MARRIAGE = "MARR"
"""Value: `MARR`.
-A legal, common-law, or customary event of creating a family unit of a man and a woman as husband and wife."""
+A legal, common-law, or customary event of creating a family unit of a man and
+a woman as husband and wife."""
+
+GEDCOM_TAG_MARR_SETTLEMENT = "MARS"
+"""Value: `MARS`.
+
+An event of creating an agreement between two people contemplating marriage,
+at which time they agree to release or modify property rights that would
+otherwise arise from the marriage."""
+
+GEDCOM_TAG_MEDIA = "MEDI"
+"""Value: `MEDI`.
+
+Identifies information about the media or having to do with the medium in which
+information is stored."""
GEDCOM_TAG_NAME = "NAME"
"""Value: `NAME`.
-A word or combination of words used to help identify an individual, title, or other item.
-More than one NAME line should be used for people who were known by multiple names."""
+A word or combination of words used to help identify an individual, title, or
+other item. More than one `NAME` line should be used for people who were known
+by multiple names."""
+
+GEDCOM_TAG_NATIONALITY = "NATI"
+"""Value: `NATI`
+
+The national heritage of an individual."""
+
+GEDCOM_TAG_NATURALIZATION = "NATU"
+"""Value: `NATU`
+
+The event of obtaining citizenship."""
+
+GEDCOM_TAG_CHILDREN_COUNT = "NCHI"
+"""Value: `NCHI`
+
+The number of children that this person is known to be the parent of (all
+marriages) when subordinate to an individual, or that belong to this family
+when subordinate to a `gedcom.tags.GEDCOM_TAG_FAMILY` record."""
+
+GEDCOM_TAG_NICKNAME = "NICK"
+"""Value: `NICK`
+
+A descriptive or familiar that is used instead of, or in addition to, one's
+proper name."""
+
+GEDCOM_TAG_MARRIAGE_COUNT = "NMR"
+"""Value: `NMR`
+
+The number of times this person has participated in a family as a spouse or
+parent."""
+
+GEDCOM_TAG_NOTE = "NOTE"
+"""Value: `NOTE`
+
+Additional information provided by the submitter for understanding the
+enclosing data."""
+
+GEDCOM_TAG_NAME_PREFIX = "NPFX"
+"""Value: `NPFX`
+
+Text which appears on a name line before the given and surname parts of a name.
+i.e. ( Lt. Cmndr. ) Joseph /Allen/ jr. In this example Lt. Cmndr. is considered
+as the name prefix portion."""
+
+GEDCOM_TAG_NAME_SUFFIX = "NSFX"
+"""Value: `NSFX`
+
+Text which appears on a name line after or behind the given and surname parts
+of a name. i.e. Lt. Cmndr. Joseph /Allen/ ( jr. ) In this example jr. is
+considered as the name suffix portion."""
GEDCOM_TAG_OBJECT = "OBJE"
"""Value: `OBJE`
-Pertaining to a grouping of attributes used in describing something. Usually referring to the data required
-to represent a multimedia object, such an audio recording, a photograph of a person, or an image of a document."""
+Pertaining to a grouping of attributes used in describing something. Usually
+referring to the data required to represent a multimedia object, such an audio
+recording, a photograph of a person, or an image of a document."""
GEDCOM_TAG_OCCUPATION = "OCCU"
"""Value: `OCCU`
The type of work or profession of an individual."""
+GEDCOM_TAG_ORDINANCE = "ORDI"
+"""Value: `ORDI`
+
+Pertaining to a religious ordinance in general."""
+
+GEDCOM_TAG_ORDINATION = "ORDN"
+"""Value: `ORDN`
+
+A religious event of receiving authority to act in religious matters."""
+
+GEDCOM_TAG_PAGE = "PAGE"
+"""Value: `PAGE`
+
+A number or description to identify where information can be found in a
+referenced work."""
+
+GEDCOM_TAG_PEDIGREE = "PEDI"
+"""Value: `PEDI`
+
+Information pertaining to an individual to parent lineage chart."""
+
+GEDCOM_TAG_PHONE = "PHON"
+"""Value: `PHON`
+
+A unique number assigned to access a specific telephone."""
+
GEDCOM_TAG_PLACE = "PLAC"
"""Value: `PLAC`
A jurisdictional name to identify the place or location of an event."""
+GEDCOM_TAG_POSTAL_CODE = "POST"
+"""Value: `POST`
+
+A code used by a postal service to identify an area to facilitate mail handling."""
+
GEDCOM_TAG_PRIVATE = "PRIV"
"""Value: `PRIV`
Flag for private address or event."""
+GEDCOM_TAG_PROBATE = "PROB"
+"""Value: `PROB`
+
+An event of judicial determination of the validity of a will. May indicate
+several related court activities over several dates."""
+
+GEDCOM_TAG_PROPERTY = "PROP"
+"""Value: `PROP`
+
+Pertaining to possessions such as real estate or other property of interest."""
+
+GEDCOM_TAG_PUBLICATION = "PUBL"
+"""Value: `PUBL`
+
+Refers to when and/or were a work was published or created."""
+
+GEDCOM_TAG_QUALITY_OF_DATA = "QUAY"
+"""Value: `QUAY`
+
+An assessment of the certainty of the evidence to support the conclusion drawn
+from evidence."""
+
+GEDCOM_TAG_REFERENCE = "REFN"
+"""Value: `REFN`
+
+A description or number used to identify an item for filing, storage, or other
+reference purposes."""
+
+GEDCOM_TAG_RELATIONSHIP = "RELA"
+"""Value: `RELA`
+
+A relationship value between the indicated contexts."""
+
+GEDCOM_TAG_RELIGION = "RELI"
+"""Value: `RELI`
+
+A religious denomination to which a person is affiliated or for which a record
+applies."""
+
+GEDCOM_TAG_REPOSITORY = "REPO"
+"""Value: `REPO`
+
+An institution or person that has the specified item as part of their
+collection(s)."""
+
+GEDCOM_TAG_RESIDENCE = "RESI"
+"""Value: `RESI`
+
+The act of dwelling at a place for a period of time."""
+
+GEDCOM_TAG_RESTRICTION = "RESN"
+"""Value: `RESN`
+
+A processing indicator signifying access to information has been denied or
+otherwise restricted."""
+
+GEDCOM_TAG_RETIREMENT = "RETI"
+"""Value: `RETI`
+
+An event of exiting an occupational relationship with an employer after a
+qualifying time period."""
+
+GEDCOM_TAG_REC_FILE_NUMBER = "RFN"
+"""Value: `RFN`
+
+A permanent number assigned to a record that uniquely identifies it within a
+known file."""
+
+GEDCOM_TAG_REC_ID_NUMBER = "RIN"
+"""Value: `RIN`
+
+A number assigned to a record by an originating automated system that can be
+used by a receiving system to report results pertaining to that record."""
+
+GEDCOM_TAG_ROLE = "ROLE"
+"""Value: `ROLE`
+
+A name given to a role played by an individual in connection with an event."""
+
+GEDCOM_TAG_ROMANIZED = "ROMN"
+"""Value: `ROMN`
+
+A romanized variation of a superior text string."""
+
GEDCOM_TAG_SEX = "SEX"
"""Value: `SEX`
Indicates the sex of an individual--male or female."""
+GEDCOM_TAG_SEALING_CHILD = "SLGC"
+"""Value: `SLGC`
+
+A religious event pertaining to the sealing of a child to his or her parents in
+an LDS temple ceremony."""
+
+GEDCOM_TAG_SEALING_SPOUSE = "SLGS"
+"""Value: `SLGS`
+
+A religious event pertaining to the sealing of a husband and wife in an LDS
+temple ceremony."""
+
GEDCOM_TAG_SOURCE = "SOUR"
"""Value: `SOUR`
The initial or original material from which information was obtained."""
+GEDCOM_TAG_SURN_PREFIX = "SPFX"
+"""Value: `SPFX`
+
+A name piece used as a non-indexing pre-part of a surname."""
+
+GEDCOM_TAG_SOC_SEC_NUMBER = "SSN"
+"""Value: `SSN`
+
+A number assigned by the United States Social Security Administration. Used for
+tax identification purposes."""
+
+GEDCOM_TAG_STATE = "STAE"
+"""Value: `STAE`
+
+A geographical division of a larger jurisdictional area, such as a State within
+the United States of America."""
+
+GEDCOM_TAG_STATUS = "STAT"
+"""Value: `STAT`
+
+An assessment of the state or condition of something."""
+
+GEDCOM_TAG_SUBMITTER = "SUBM"
+"""Value: `SUBM`
+
+An individual or organization who contributes genealogical data to a file or
+transfers it to someone else."""
+
+GEDCOM_TAG_SUBMISSION = "SUBN"
+"""Value: `SUBN`
+
+Pertains to a collection of data issued for processing."""
+
GEDCOM_TAG_SURNAME = "SURN"
"""Value: `SURN`
A family name passed on or used by members of a family."""
+GEDCOM_TAG_TEMPLE = "TEMP"
+"""Value: `TEMP`
+
+The name or code that represents the name a temple of the LDS Church."""
+
+GEDCOM_TAG_TEXT = "TEXT"
+"""Value: `TEXT`
+
+The exact wording found in an original source document."""
+
+GEDCOM_TAG_TIME = "TIME"
+"""Value: `TIME`
+
+A time value in a 24-hour clock format, including hours, minutes, and optional
+seconds, separated by a colon (:). Fractions of seconds are shown in decimal
+notation."""
+
+GEDCOM_TAG_TITLE = "TITL"
+"""Value: `TITL`
+
+A description of a specific writing or other work, such as the title of a book
+when used in a source context, or a formal designation used by an individual
+in connection with positions of royalty or other social status, such as Grand
+Duke."""
+
+GEDCOM_TAG_TRAILER = "TRLR"
+"""Value: `TRLR`
+
+At level 0, specifies the end of a GEDCOM transmission."""
+
+GEDCOM_TAG_TYPE = "TYPE"
+"""Value: `TYPE`
+
+A further qualification to the meaning of the associated superior tag. The value
+does not have any computer processing reliability. It is more in the form of a
+short one or two word note that should be displayed any time the associated data
+is displayed."""
+
+GEDCOM_TAG_VERSION = "VERS"
+"""Value: `VERS`
+
+Indicates which version of a product, item, or publication is being used or
+referenced."""
+
GEDCOM_TAG_WIFE = "WIFE"
"""Value: `WIFE`
An individual in the role as a mother and/or married woman."""
+
+GEDCOM_TAG_WWW = "WWW"
+"""Value: `WWW`
+
+World Wide Web home page."""
+
+GEDCOM_TAG_WILL = "WILL"
+"""Value: `WILL`
+
+A legal document treated as an event, by which a person disposes of his or her
+estate, to take effect after death. The event date is the date the will was
+signed while the person was alive. (See also `gedcom.tags.GEDCOM_TAG_PROBATE`)"""
diff --git a/tests/element/test_file.py b/tests/element/test_file.py
deleted file mode 100644
index fc13189..0000000
--- a/tests/element/test_file.py
+++ /dev/null
@@ -1,9 +0,0 @@
-from gedcom.element.element import Element
-from gedcom.element.file import FileElement
-import gedcom.tags
-
-
-def test_initialization():
- file_element = FileElement(level=-1, pointer="", tag=gedcom.tags.GEDCOM_TAG_FILE, value="")
- assert isinstance(file_element, Element)
- assert isinstance(file_element, FileElement)
diff --git a/tests/element/test_header.py b/tests/element/test_header.py
new file mode 100644
index 0000000..a212af7
--- /dev/null
+++ b/tests/element/test_header.py
@@ -0,0 +1,9 @@
+from gedcom.element.element import Element
+from gedcom.element.header import HeaderElement
+import gedcom.tags
+
+
+def test_initialization():
+ header_element = HeaderElement(level=-1, pointer="", tag=gedcom.tags.GEDCOM_TAG_HEADER, value="")
+ assert isinstance(header_element, Element)
+ assert isinstance(header_element, HeaderElement)
diff --git a/tests/element/test_note.py b/tests/element/test_note.py
new file mode 100644
index 0000000..92cd521
--- /dev/null
+++ b/tests/element/test_note.py
@@ -0,0 +1,9 @@
+from gedcom.element.element import Element
+from gedcom.element.note import NoteElement
+import gedcom.tags
+
+
+def test_initialization():
+ note_element = NoteElement(level=-1, pointer="", tag=gedcom.tags.GEDCOM_TAG_NOTE, value="")
+ assert isinstance(note_element, Element)
+ assert isinstance(note_element, NoteElement)
diff --git a/tests/element/test_repository.py b/tests/element/test_repository.py
new file mode 100644
index 0000000..6d7bfaf
--- /dev/null
+++ b/tests/element/test_repository.py
@@ -0,0 +1,9 @@
+from gedcom.element.element import Element
+from gedcom.element.repository import RepositoryElement
+import gedcom.tags
+
+
+def test_initialization():
+ repository_element = RepositoryElement(level=-1, pointer="", tag=gedcom.tags.GEDCOM_TAG_REPOSITORY, value="")
+ assert isinstance(repository_element, Element)
+ assert isinstance(repository_element, RepositoryElement)
diff --git a/tests/element/test_source.py b/tests/element/test_source.py
new file mode 100644
index 0000000..2373695
--- /dev/null
+++ b/tests/element/test_source.py
@@ -0,0 +1,9 @@
+from gedcom.element.element import Element
+from gedcom.element.source import SourceElement
+import gedcom.tags
+
+
+def test_initialization():
+ source_element = SourceElement(level=-1, pointer="", tag=gedcom.tags.GEDCOM_TAG_SOURCE, value="")
+ assert isinstance(source_element, Element)
+ assert isinstance(source_element, SourceElement)
diff --git a/tests/element/test_submission.py b/tests/element/test_submission.py
new file mode 100644
index 0000000..1155dff
--- /dev/null
+++ b/tests/element/test_submission.py
@@ -0,0 +1,9 @@
+from gedcom.element.element import Element
+from gedcom.element.submission import SubmissionElement
+import gedcom.tags
+
+
+def test_initialization():
+ submission_element = SubmissionElement(level=-1, pointer="", tag=gedcom.tags.GEDCOM_TAG_SUBMISSION, value="")
+ assert isinstance(submission_element, Element)
+ assert isinstance(submission_element, SubmissionElement)
diff --git a/tests/element/test_submitter.py b/tests/element/test_submitter.py
new file mode 100644
index 0000000..f949d6d
--- /dev/null
+++ b/tests/element/test_submitter.py
@@ -0,0 +1,9 @@
+from gedcom.element.element import Element
+from gedcom.element.submitter import SubmitterElement
+import gedcom.tags
+
+
+def test_initialization():
+ submitter_element = SubmitterElement(level=-1, pointer="", tag=gedcom.tags.GEDCOM_TAG_SUBMITTER, value="")
+ assert isinstance(submitter_element, Element)
+ assert isinstance(submitter_element, SubmitterElement)
diff --git a/tests/test_parser.py b/tests/test_parser.py
index 451a3fa..615a347 100644
--- a/tests/test_parser.py
+++ b/tests/test_parser.py
@@ -62,7 +62,7 @@ def test_parse_from_string():
4 LONG W122.234319
"""
gedcom_parser = Parser()
- gedcom_parser.parse([(a + '\n').encode('utf-8-sig') for a in case_1.splitlines()])
+ gedcom_parser.parse([(a + '\n') for a in case_1.splitlines()])
element_1 = gedcom_parser.get_root_child_elements()[0]
assert isinstance(element_1, IndividualElement)
assert element_1.get_tag() == 'INDI'
@@ -86,7 +86,7 @@ def test_parse_from_string():
2 _FREL Natural
2 _MREL Natural
"""
- gedcom_parser.parse([(a + '\n').encode('utf-8-sig') for a in case_2.splitlines()])
+ gedcom_parser.parse([(a + '\n') for a in case_2.splitlines()])
element_2 = gedcom_parser.get_root_child_elements()[0]
assert element_2.get_tag() == 'FAM'
assert element_2.get_pointer() == '@F28@'
@@ -112,7 +112,7 @@ def test_to_gedcom_string():
"""
gedcom_parser = Parser()
- gedcom_parser.parse([(a + '\n').encode('utf-8-sig') for a in case_1.splitlines()])
+ gedcom_parser.parse([(a + '\n') for a in case_1.splitlines()])
case_1_string_array = case_1.splitlines()
gedcom_string = gedcom_parser.to_gedcom_string(True)
diff --git a/tox.ini b/tox.ini
index 8cca615..2f00a83 100644
--- a/tox.ini
+++ b/tox.ini
@@ -13,6 +13,8 @@ basepython =
py37: python3.7
py38: python3.8
deps =
+ chardet
+ ansel
check-manifest
flake8
pytest