import requests
except ImportError:
sys.stderr.write('You need to install the requests module first\n')
- sys.stderr.write('(run this in your terminal: "python3 -m pip install requests" or "python3 -m pip install --user requests")\n')
+ sys.stderr.write(
+ '(run this in your terminal: "python3 -m pip install requests" or "python3 -m pip install --user requests")\n')
exit(2)
+FACT_TAGS = {
+ 'http://gedcomx.org/Birth': 'BIRT',
+ 'http://gedcomx.org/Christening': 'CHR',
+ 'http://gedcomx.org/Death': 'DEAT',
+ 'http://gedcomx.org/Burial': 'BURI',
+ 'http://gedcomx.org/PhysicalDescription': 'DSCR',
+ 'http://gedcomx.org/Occupation': 'OCCU',
+ 'http://gedcomx.org/MilitaryService': '_MILT',
+ 'http://gedcomx.org/Marriage': 'MARR',
+ 'http://gedcomx.org/Divorce': 'DIV',
+ 'http://gedcomx.org/Annulment': 'ANUL',
+ 'http://gedcomx.org/CommonLawMarriage': '_COML'
+}
+
# FamilySearch session class
class Session:
try:
url = 'https://www.familysearch.org/auth/familysearch/login'
if self.verbose:
- self.logfile.write('[' + time.strftime("%Y-%m-%d %H:%M:%S") + ']: Downloading: ' + url + '\n')
- r = requests.get(url, params={'ldsauth': False}, allow_redirects=False)
+ self.logfile.write(
+ '[' + time.strftime("%Y-%m-%d %H:%M:%S") + ']: Downloading: ' + url + '\n')
+ r = requests.get(
+ url, params={'ldsauth': False}, allow_redirects=False)
url = r.headers['Location']
if self.verbose:
- self.logfile.write('[' + time.strftime("%Y-%m-%d %H:%M:%S") + ']: Downloading: ' + url + '\n')
+ self.logfile.write(
+ '[' + time.strftime("%Y-%m-%d %H:%M:%S") + ']: Downloading: ' + url + '\n')
r = requests.get(url, allow_redirects=False)
idx = r.text.index('name="params" value="')
span = r.text[idx + 21:].index('"')
url = 'https://ident.familysearch.org/cis-web/oauth2/v3/authorization'
if self.verbose:
- self.logfile.write('[' + time.strftime("%Y-%m-%d %H:%M:%S") + ']: Downloading: ' + url + '\n')
- r = requests.post(url, data={'params': params, 'userName': self.username, 'password': self.password}, allow_redirects=False)
+ self.logfile.write(
+ '[' + time.strftime("%Y-%m-%d %H:%M:%S") + ']: Downloading: ' + url + '\n')
+ r = requests.post(url, data={
+ 'params': params, 'userName': self.username, 'password': self.password}, allow_redirects=False)
if 'The username or password was incorrect' in r.text:
if self.verbose:
- self.logfile.write('[' + time.strftime("%Y-%m-%d %H:%M:%S") + ']: The username or password was incorrect\n')
+ self.logfile.write(
+ '[' + time.strftime("%Y-%m-%d %H:%M:%S") + ']: The username or password was incorrect\n')
exit()
if 'Invalid Oauth2 Request' in r.text:
if self.verbose:
- self.logfile.write('[' + time.strftime("%Y-%m-%d %H:%M:%S") + ']: Invalid Oauth2 Request\n')
+ self.logfile.write(
+ '[' + time.strftime("%Y-%m-%d %H:%M:%S") + ']: Invalid Oauth2 Request\n')
time.sleep(self.timeout)
continue
url = r.headers['Location']
if self.verbose:
- self.logfile.write('[' + time.strftime("%Y-%m-%d %H:%M:%S") + ']: Downloading: ' + url + '\n')
+ self.logfile.write(
+ '[' + time.strftime("%Y-%m-%d %H:%M:%S") + ']: Downloading: ' + url + '\n')
r = requests.get(url, allow_redirects=False)
self.fssessionid = r.cookies['fssessionid']
except requests.exceptions.ReadTimeout:
if self.verbose:
- self.logfile.write('[' + time.strftime("%Y-%m-%d %H:%M:%S") + ']: Read timed out\n')
+ self.logfile.write(
+ '[' + time.strftime("%Y-%m-%d %H:%M:%S") + ']: Read timed out\n')
continue
except requests.exceptions.ConnectionError:
if self.verbose:
- self.logfile.write('[' + time.strftime("%Y-%m-%d %H:%M:%S") + ']: Connection aborted\n')
+ self.logfile.write(
+ '[' + time.strftime("%Y-%m-%d %H:%M:%S") + ']: Connection aborted\n')
time.sleep(self.timeout)
continue
except requests.exceptions.HTTPError:
if self.verbose:
- self.logfile.write('[' + time.strftime("%Y-%m-%d %H:%M:%S") + ']: HTTPError\n')
+ self.logfile.write(
+ '[' + time.strftime("%Y-%m-%d %H:%M:%S") + ']: HTTPError\n')
time.sleep(self.timeout)
continue
except KeyError:
if self.verbose:
- self.logfile.write('[' + time.strftime("%Y-%m-%d %H:%M:%S") + ']: KeyError\n')
+ self.logfile.write(
+ '[' + time.strftime("%Y-%m-%d %H:%M:%S") + ']: KeyError\n')
time.sleep(self.timeout)
continue
except ValueError:
if self.verbose:
- self.logfile.write('[' + time.strftime("%Y-%m-%d %H:%M:%S") + ']: ValueError\n')
+ self.logfile.write(
+ '[' + time.strftime("%Y-%m-%d %H:%M:%S") + ']: ValueError\n')
time.sleep(self.timeout)
continue
if self.verbose:
- self.logfile.write('[' + time.strftime("%Y-%m-%d %H:%M:%S") + ']: FamilySearch session id: ' + self.fssessionid + '\n')
+ self.logfile.write('[' + time.strftime("%Y-%m-%d %H:%M:%S") +
+ ']: FamilySearch session id: ' + self.fssessionid + '\n')
return
# retrieve FamilySearch developer key (wget -O- --max-redirect 0 https://familysearch.org/auth/familysearch/login?ldsauth=false)
url = 'https://familysearch.org/auth/familysearch/login'
while True:
if self.verbose:
- self.logfile.write('[' + time.strftime("%Y-%m-%d %H:%M:%S") + ']: Downloading: ' + url + '\n')
+ self.logfile.write(
+ '[' + time.strftime("%Y-%m-%d %H:%M:%S") + ']: Downloading: ' + url + '\n')
try:
- r = requests.get(url, params={'ldsauth': False}, allow_redirects=False, timeout=self.timeout)
+ r = requests.get(
+ url, params={'ldsauth': False}, allow_redirects=False, timeout=self.timeout)
location = r.headers['Location']
idx = location.index('client_id=')
key = location[idx + 10:idx + 49]
except ValueError:
if self.verbose:
- self.logfile.write('[' + time.strftime("%Y-%m-%d %H:%M:%S") + ']: FamilySearch developer key not found\n')
+ self.logfile.write(
+ '[' + time.strftime("%Y-%m-%d %H:%M:%S") + ']: FamilySearch developer key not found\n')
time.sleep(self.timeout)
continue
if self.verbose:
- self.logfile.write('[' + time.strftime("%Y-%m-%d %H:%M:%S") + ']: FamilySearch developer key: ' + key + '\n')
+ self.logfile.write(
+ '[' + time.strftime("%Y-%m-%d %H:%M:%S") + ']: FamilySearch developer key: ' + key + '\n')
return key
# retrieve FamilySearch session ID (https://familysearch.org/developers/docs/guides/oauth1/login)
def old_login(self, oldmethod=False):
url = 'https://api.familysearch.org/identity/v2/login'
- data = {'key': self.key, 'username': self.username, 'password': self.password}
+ data = {'key': self.key, 'username': self.username,
+ 'password': self.password}
while True:
if self.verbose:
- self.logfile.write('[' + time.strftime("%Y-%m-%d %H:%M:%S") + ']: Downloading: ' + url + '\n')
+ self.logfile.write(
+ '[' + time.strftime("%Y-%m-%d %H:%M:%S") + ']: Downloading: ' + url + '\n')
try:
r = requests.post(url, data, timeout=self.timeout)
except requests.exceptions.ReadTimeout:
if self.verbose:
- self.logfile.write('[' + time.strftime("%Y-%m-%d %H:%M:%S") + ']: Read timed out\n')
+ self.logfile.write(
+ '[' + time.strftime("%Y-%m-%d %H:%M:%S") + ']: Read timed out\n')
continue
except requests.exceptions.ConnectionError:
if self.verbose:
- self.logfile.write('[' + time.strftime("%Y-%m-%d %H:%M:%S") + ']: Connection aborted\n')
+ self.logfile.write(
+ '[' + time.strftime("%Y-%m-%d %H:%M:%S") + ']: Connection aborted\n')
time.sleep(self.timeout)
continue
if self.verbose:
- self.logfile.write('[' + time.strftime("%Y-%m-%d %H:%M:%S") + ']: Status code: ' + str(r.status_code) + '\n')
+ self.logfile.write(
+ '[' + time.strftime("%Y-%m-%d %H:%M:%S") + ']: Status code: ' + str(r.status_code) + '\n')
if r.status_code == 401:
- self.logfile.write('[' + time.strftime("%Y-%m-%d %H:%M:%S") + ']: Login failure\n')
+ self.logfile.write(
+ '[' + time.strftime("%Y-%m-%d %H:%M:%S") + ']: Login failure\n')
raise Exception('Login failure')
try:
r.raise_for_status()
except requests.exceptions.HTTPError:
if self.verbose:
- self.logfile.write('[' + time.strftime("%Y-%m-%d %H:%M:%S") + ']: HTTPError\n')
+ self.logfile.write(
+ '[' + time.strftime("%Y-%m-%d %H:%M:%S") + ']: HTTPError\n')
time.sleep(self.timeout)
continue
self.fssessionid = r.cookies['fssessionid']
if self.verbose:
- self.logfile.write('[' + time.strftime("%Y-%m-%d %H:%M:%S") + ']: FamilySearch session id: ' + self.fssessionid + '\n')
+ self.logfile.write('[' + time.strftime("%Y-%m-%d %H:%M:%S") +
+ ']: FamilySearch session id: ' + self.fssessionid + '\n')
return
# retrieve JSON structure from FamilySearch URL
while True:
try:
if self.verbose:
- self.logfile.write('[' + time.strftime("%Y-%m-%d %H:%M:%S") + ']: Downloading: ' + url + '\n')
+ self.logfile.write(
+ '[' + time.strftime("%Y-%m-%d %H:%M:%S") + ']: Downloading: ' + url + '\n')
# r = requests.get(url, cookies = { 's_vi': self.s_vi, 'fssessionid' : self.fssessionid }, timeout = self.timeout)
- r = requests.get(url, cookies={'fssessionid': self.fssessionid}, timeout=self.timeout)
+ r = requests.get(
+ url, cookies={'fssessionid': self.fssessionid}, timeout=self.timeout)
except requests.exceptions.ReadTimeout:
if self.verbose:
- self.logfile.write('[' + time.strftime("%Y-%m-%d %H:%M:%S") + ']: Read timed out\n')
+ self.logfile.write(
+ '[' + time.strftime("%Y-%m-%d %H:%M:%S") + ']: Read timed out\n')
continue
except requests.exceptions.ConnectionError:
if self.verbose:
- self.logfile.write('[' + time.strftime("%Y-%m-%d %H:%M:%S") + ']: Connection aborted\n')
+ self.logfile.write(
+ '[' + time.strftime("%Y-%m-%d %H:%M:%S") + ']: Connection aborted\n')
time.sleep(self.timeout)
continue
if self.verbose:
- self.logfile.write('[' + time.strftime("%Y-%m-%d %H:%M:%S") + ']: Status code: ' + str(r.status_code) + '\n')
+ self.logfile.write(
+ '[' + time.strftime("%Y-%m-%d %H:%M:%S") + ']: Status code: ' + str(r.status_code) + '\n')
if r.status_code == 204 or r.status_code == 410:
return None
if r.status_code == 401:
r.raise_for_status()
except requests.exceptions.HTTPError:
if self.verbose:
- self.logfile.write('[' + time.strftime("%Y-%m-%d %H:%M:%S") + ']: HTTPError\n')
+ self.logfile.write(
+ '[' + time.strftime("%Y-%m-%d %H:%M:%S") + ']: HTTPError\n')
if r.status_code == 403:
if 'message' in r.json()['errors'][0] and r.json()['errors'][0]['message'] == u'Unable to get ordinances.':
- self.logfile.write('Unable to get ordinances. Try with an LDS account or without option -c.\n')
+ self.logfile.write(
+ 'Unable to get ordinances. Try with an LDS account or without option -c.\n')
exit()
else:
- self.logfile.write('Warning code 403 link: ' + url + ' ' + r.json()['errors'][0]['message'] or '')
+ self.logfile.write(
+ 'Warning code 403 link: ' + url + ' ' + r.json()['errors'][0]['message'] or '')
return None
time.sleep(self.timeout)
continue
self.text = text.strip()
def print(self, file=sys.stdout):
- file.write('0 @N' + str(self.num) + '@ NOTE ' + self.text.replace('\n', '\n1 CONT ') + '\n')
+ file.write('0 @N' + str(self.num) + '@ NOTE ' +
+ self.text.replace('\n', '\n1 CONT ') + '\n')
def link(self, file=sys.stdout, level=1):
file.write(str(level) + ' NOTE @N' + str(self.num) + '@\n')
if data:
self.fid = data['id']
if 'about' in data:
- self.url = data['about'].replace('familysearch.org/platform/memories/memories', 'www.familysearch.org/photos/artifacts')
+ self.url = data['about'].replace(
+ 'familysearch.org/platform/memories/memories', 'www.familysearch.org/photos/artifacts')
if 'citations' in data:
self.citation = data['citations'][0]['value']
if data['titles']:
if self.title:
file.write('1 TITL ' + self.title.replace('\n', '\n2 CONT ') + '\n')
if self.citation:
- file.write('1 AUTH ' + self.citation.replace('\n', '\n2 CONT ') + '\n')
+ file.write(
+ '1 AUTH ' + self.citation.replace('\n', '\n2 CONT ') + '\n')
if self.url:
file.write('1 PUBL ' + self.url.replace('\n', '\n2 CONT ') + '\n')
for n in self.notes:
self.place = data['place']['original']
if 'changeMessage' in data['attribution']:
self.note = Note(data['attribution']['changeMessage'], tree)
+ if self.type == 'http://gedcomx.org/Death' and not any([self.date, self.place]):
+ self.value = 'Y'
def print(self, file=sys.stdout, key=None):
- if key:
- file.write('1 ' + key)
- if self.value:
- file.write(' ' + self.value)
- file.write('\n')
- if self.date:
- file.write('2 DATE ' + self.date + '\n')
- if self.place:
- file.write('2 PLAC ' + self.place + '\n')
- if self.note:
- self.note.link(file, 2)
+ if self.type in FACT_TAGS:
+ file.write('1 ' + FACT_TAGS[self.type])
+ elif self.type[:6] == u'data:,':
+ file.write('1 EVEN\n2 TYPE ' +
+ self.type[6:] + '\n2 NOTE Description:')
+ else:
+ return
+ if self.value:
+ file.write(' ' + self.value)
+ file.write('\n')
+ if self.date:
+ file.write('2 DATE ' + self.date + '\n')
+ if self.place:
+ file.write('2 PLAC ' + self.place + '\n')
+ if self.note:
+ self.note.link(file, 2)
+
class Memorie:
if 'titles' in data:
self.description = data['titles'][0]['value']
if 'descriptions' in data:
- self.description = ('' if not self.description else self.description + '\n') + data['descriptions'][0]['value']
- # self.description = (self.description or '') + '\n' + data['descriptions'][0]['value']
+ self.description = (
+ '' if not self.description else self.description + '\n') + data['descriptions'][0]['value']
def print(self, file=sys.stdout):
file.write('1 OBJE\n2 FORM URL\n')
if self.description:
- file.write('2 TITL ' + self.description.replace('\n', '\n2 CONT ') + '\n')
+ file.write(
+ '2 TITL ' + self.description.replace('\n', '\n2 CONT ') + '\n')
if self.url:
file.write('2 FILE ' + self.url + '\n')
+
class Name:
def __init__(self, data=None, tree=None):
self.num = Indi.counter
self.fid = fid
self.tree = tree
- self.living = True
self.famc_fid = set()
self.fams_fid = set()
self.famc_num = set()
self.fams_num = set()
self.name = None
- self.gender = self.birtdate = self.birtplac = self.deatdate = self.deatplac = None
- self.chrdate = self.chrplac = self.buridate = self.buriplac = None
+ self.gender = None
self.baptism = self.confirmation = self.endowment = self.sealing_child = None
- self.physical_descriptions = set()
self.nicknames = set()
- self.occupations = set()
- self.military = set()
+ self.facts = set()
self.birthnames = set()
self.married = set()
self.aka = set()
data = tree.fs.get_url(url)
if data:
x = data['persons'][0]
- self.living = x['living']
if x['names']:
for y in x['names']:
if y['preferred']:
elif x['gender']['type'] == 'http://gedcomx.org/Unknown':
self.gender = 'U'
for y in x['facts']:
- if y['type'] == u'http://gedcomx.org/Birth':
- self.birtdate = y['date']['original'] if 'date' in y and 'original' in y['date'] else None
- self.birtplac = y['place']['original'] if 'place' in y and 'original' in y['place'] else None
- if y['type'] == u'http://gedcomx.org/Christening':
- self.chrdate = y['date']['original'] if 'date' in y and 'original' in y['date'] else None
- self.chrplac = y['place']['original'] if 'place' in y and 'original' in y['place'] else None
- if y['type'] == u'http://gedcomx.org/Death':
- self.deatdate = y['date']['original'] if 'date' in y and 'original' in y['date'] else None
- self.deatplac = y['place']['original'] if 'place' in y and 'original' in y['place'] else None
- if y['type'] == u'http://gedcomx.org/Burial':
- self.buridate = y['date']['original'] if 'date' in y and 'original' in y['date'] else None
- self.buriplac = y['place']['original'] if 'place' in y and 'original' in y['place'] else None
- if y['type'] == u'http://gedcomx.org/PhysicalDescription':
- self.physical_descriptions.add(Fact(y, self.tree))
- if y['type'] == u'http://gedcomx.org/Occupation':
- self.occupations.add(Fact(y, self.tree))
- if y['type'] == u'http://gedcomx.org/MilitaryService':
- self.military.add(Fact(y, self.tree))
if y['type'] == u'http://familysearch.org/v1/LifeSketch':
- self.notes.add(Note('=== Life Sketch ===\n' + y['value'], self.tree))
+ self.notes.add(
+ Note('=== Life Sketch ===\n' + y['value'], self.tree))
+ else:
+ self.facts.add(Fact(y, self.tree))
if 'sources' in x:
for y in x['sources']:
source = self.tree.add_source(y['descriptionId'])
if source:
if 'changeMessage' in y['attribution']:
- self.sources.add((source, y['attribution']['changeMessage']))
+ self.sources.add(
+ (source, y['attribution']['changeMessage']))
else:
self.sources.add((source,))
if 'evidence' in x:
url = 'https://familysearch.org/platform/tree/persons/%s/spouses.json' % self.fid
data = self.tree.fs.get_url(url)
if data and 'relationships' in data:
- self.spouses = [(x['person1']['resourceId'], x['person2']['resourceId'], x['id']) for x in data['relationships']]
+ self.spouses = [(x['person1']['resourceId'], x['person2']
+ ['resourceId'], x['id']) for x in data['relationships']]
return self.spouses
# retrieve individual notes
def get_notes(self):
- notes = self.tree.fs.get_url('https://familysearch.org/platform/tree/persons/%s/notes.json' % self.fid)
+ notes = self.tree.fs.get_url(
+ 'https://familysearch.org/platform/tree/persons/%s/notes.json' % self.fid)
if notes:
for n in notes['persons'][0]['notes']:
- text_note = '===' + n['subject'] + '===\n' if 'subject' in n else ''
+ text_note = '===' + n['subject'] + \
+ '===\n' if 'subject' in n else ''
text_note += n['text'] + '\n' if 'text' in n else ''
self.notes.add(Note(text_note, self.tree))
if o['type'] == u'http://lds.org/SealingChildToParents':
self.sealing_child = Ordinance(o)
if 'father' in o and 'mother' in o:
- famc = (o['father']['resourceId'], o['mother']['resourceId'])
+ famc = (o['father']['resourceId'],
+ o['mother']['resourceId'])
if o['type'] == u'http://lds.org/SealingToSpouse':
res.append(o)
return res, famc
# retrieve contributors
def get_contributors(self):
temp = set()
- data = self.tree.fs.get_url('https://familysearch.org/platform/tree/persons/%s/changes.json' % self.fid)
+ data = self.tree.fs.get_url(
+ 'https://familysearch.org/platform/tree/persons/%s/changes.json' % self.fid)
for entries in data['entries']:
for contributors in entries['contributors']:
temp.add(contributors['name'])
o.print(file, 'married')
if self.gender:
file.write('1 SEX ' + self.gender + '\n')
- if self.birtdate or self.birtplac:
- file.write('1 BIRT\n')
- if self.birtdate:
- file.write('2 DATE ' + self.birtdate + '\n')
- if self.birtplac:
- file.write('2 PLAC ' + self.birtplac + '\n')
- if self.chrdate or self.chrplac:
- file.write('1 CHR\n')
- if self.chrdate:
- file.write('2 DATE ' + self.chrdate + '\n')
- if self.chrplac:
- file.write('2 PLAC ' + self.chrplac + '\n')
- if self.deatdate or self.deatplac:
- file.write('1 DEAT\n')
- if self.deatdate:
- file.write('2 DATE ' + self.deatdate + '\n')
- if self.deatplac:
- file.write('2 PLAC ' + self.deatplac + '\n')
- elif not self.living:
- file.write('1 DEAT Y\n')
- if self.buridate or self.buriplac:
- file.write('1 BURI\n')
- if self.buridate:
- file.write('2 DATE ' + self.buridate + '\n')
- if self.buriplac:
- file.write('2 PLAC ' + self.buriplac + '\n')
- for o in self.physical_descriptions:
- o.print(file, 'DSCR')
+ for o in self.facts:
+ o.print(file)
+ for o in self.memories:
+ o.print(file)
if self.baptism:
file.write('1 BAPL\n')
self.baptism.print(file)
file.write('1 FAMS @F' + str(num) + '@\n')
for num in self.famc_num:
file.write('1 FAMC @F' + str(num) + '@\n')
- for o in self.memories:
- o.print(file)
- for o in self.occupations:
- o.print(file, 'OCCU')
- for o in self.military:
- o.print(file, '_MILT')
file.write('1 _FSFTID ' + self.fid + '\n')
for o in self.notes:
o.link(file)
self.wife_fid = wife if wife else None
self.tree = tree
self.husb_num = self.wife_num = self.fid = None
- self.marriage_facts = set()
+ self.facts = set()
self.sealing_spouse = None
self.chil_fid = set()
self.chil_num = set()
data = self.tree.fs.get_url(url)
if data and 'facts' in data['relationships'][0]:
for x in data['relationships'][0]['facts']:
- self.marriage_facts.add(Fact(x, self.tree))
+ self.facts.add(Fact(x, self.tree))
if data and 'sources' in data['relationships'][0]:
for y in data['relationships'][0]['sources']:
source = self.tree.add_source(y['descriptionId'])
if source:
if 'changeMessage' in y['attribution']:
- self.sources.add((source, y['attribution']['changeMessage']))
+ self.sources.add(
+ (source, y['attribution']['changeMessage']))
else:
self.sources.add((source,))
# retrieve marriage notes
def get_notes(self):
if self.fid:
- notes = self.tree.fs.get_url('https://familysearch.org/platform/tree/couple-relationships/%s/notes.json' % self.fid)
+ notes = self.tree.fs.get_url(
+ 'https://familysearch.org/platform/tree/couple-relationships/%s/notes.json' % self.fid)
if notes:
for n in notes['relationships'][0]['notes']:
- text_note = '===' + n['subject'] + '===\n' if 'subject' in n else ''
+ text_note = '===' + n['subject'] + \
+ '===\n' if 'subject' in n else ''
text_note += n['text'] + '\n' if 'text' in n else ''
self.notes.add(Note(text_note, self.tree))
def get_contributors(self):
if self.fid:
temp = set()
- data = self.tree.fs.get_url('https://familysearch.org/platform/tree/couple-relationships/%s/changes.json' % self.fid)
+ data = self.tree.fs.get_url(
+ 'https://familysearch.org/platform/tree/couple-relationships/%s/changes.json' % self.fid)
for entries in data['entries']:
for contributors in entries['contributors']:
temp.add(contributors['name'])
file.write('1 WIFE @I' + str(self.wife_num) + '@\n')
for num in self.chil_num:
file.write('1 CHIL @I' + str(num) + '@\n')
- for o in self.marriage_facts:
- key = ''
- if o.type == u'http://gedcomx.org/Marriage':
- key = 'MARR'
- if o.type == u'http://gedcomx.org/Divorce':
- key = 'DIV'
- if o.type == u'http://gedcomx.org/Annulment':
- key = 'ANUL'
- if o.type == u'http://gedcomx.org/CommonLawMarriage':
- key = '_COML'
- if key:
- o.print(file, key)
+ for o in self.facts:
+ o.print(file)
if self.sealing_spouse:
file.write('1 SLGS\n')
self.sealing_spouse.print(file)
self.indi[fid].sealing_child.famc = self.fam[famc]
for o in ret:
if (fid, o['spouse']['resourceId']) in self.fam:
- self.fam[(fid, o['spouse']['resourceId'])].sealing_spouse = Ordinance(o)
+ self.fam[(fid, o['spouse']['resourceId'])
+ ].sealing_spouse = Ordinance(o)
elif (o['spouse']['resourceId'], fid) in self.fam:
- self.fam[(o['spouse']['resourceId'], fid)].sealing_spouse = Ordinance(o)
+ self.fam[(o['spouse']['resourceId'], fid)
+ ].sealing_spouse = Ordinance(o)
# Find source by fid
def add_source(self, fid=None):
if fid:
if fid in self.sources:
return self.sources[fid]
- data = self.fs.get_url('https://familysearch.org/platform/sources/descriptions/%s.json' % fid)
+ data = self.fs.get_url(
+ 'https://familysearch.org/platform/sources/descriptions/%s.json' % fid)
if data:
return Source(data['sourceDescriptions'][0], self)
return False
for husb, wife in self.fam:
self.fam[(husb, wife)].husb_num = self.indi[husb].num if husb else None
self.fam[(husb, wife)].wife_num = self.indi[wife].num if wife else None
- self.fam[(husb, wife)].chil_num = set([self.indi[chil].num for chil in self.fam[(husb, wife)].chil_fid])
+ self.fam[(husb, wife)].chil_num = set(
+ [self.indi[chil].num for chil in self.fam[(husb, wife)].chil_fid])
for fid in self.indi:
- self.indi[fid].famc_num = set([self.fam[(husb, wife)].num for husb, wife in self.indi[fid].famc_fid])
- self.indi[fid].fams_num = set([self.fam[(husb, wife)].num for husb, wife in self.indi[fid].fams_fid])
+ self.indi[fid].famc_num = set(
+ [self.fam[(husb, wife)].num for husb, wife in self.indi[fid].famc_fid])
+ self.indi[fid].fams_num = set(
+ [self.fam[(husb, wife)].num for husb, wife in self.indi[fid].fams_fid])
# print GEDCOM file
def print(self, file=sys.stdout):
if __name__ == '__main__':
- parser = argparse.ArgumentParser(description='Retrieve GEDCOM data from FamilySearch Tree (4 Jul 2016)', add_help=False, usage='getmyancestors.py -u username -p password [options]')
- parser.add_argument('-u', metavar='<STR>', type=str, help='FamilySearch username')
- parser.add_argument('-p', metavar='<STR>', type=str, help='FamilySearch password')
- parser.add_argument('-i', metavar='<STR>', nargs='+', type=str, help='List of individual FamilySearch IDs for whom to retrieve ancestors')
- parser.add_argument('-a', metavar='<INT>', type=int, default=4, help='Number of generations to ascend [4]')
- parser.add_argument('-d', metavar='<INT>', type=int, default=0, help='Number of generations to descend [0]')
- parser.add_argument('-m', action="store_true", default=False, help='Add spouses and couples information [False]')
- parser.add_argument('-r', action="store_true", default=False, help='Add list of contributors in notes [False]')
- parser.add_argument('-c', action="store_true", default=False, help='Add LDS ordinances (need LDS account) [False]')
- parser.add_argument("-v", action="store_true", default=False, help="Increase output verbosity [False]")
- parser.add_argument('-t', metavar='<INT>', type=int, default=60, help='Timeout in seconds [60]')
+ parser = argparse.ArgumentParser(description='Retrieve GEDCOM data from FamilySearch Tree (4 Jul 2016)',
+ add_help=False, usage='getmyancestors.py -u username -p password [options]')
+ parser.add_argument('-u', metavar='<STR>', type=str,
+ help='FamilySearch username')
+ parser.add_argument('-p', metavar='<STR>', type=str,
+ help='FamilySearch password')
+ parser.add_argument('-i', metavar='<STR>', nargs='+', type=str,
+ help='List of individual FamilySearch IDs for whom to retrieve ancestors')
+ parser.add_argument('-a', metavar='<INT>', type=int,
+ default=4, help='Number of generations to ascend [4]')
+ parser.add_argument('-d', metavar='<INT>', type=int,
+ default=0, help='Number of generations to descend [0]')
+ parser.add_argument('-m', action="store_true", default=False,
+ help='Add spouses and couples information [False]')
+ parser.add_argument('-r', action="store_true", default=False,
+ help='Add list of contributors in notes [False]')
+ parser.add_argument('-c', action="store_true", default=False,
+ help='Add LDS ordinances (need LDS account) [False]')
+ parser.add_argument("-v", action="store_true", default=False,
+ help="Increase output verbosity [False]")
+ parser.add_argument('-t', metavar='<INT>', type=int,
+ default=60, help='Timeout in seconds [60]')
try:
- parser.add_argument('-o', metavar='<FILE>', type=argparse.FileType('w', encoding='UTF-8'), default=sys.stdout, help='output GEDCOM file [stdout]')
- parser.add_argument('-l', metavar='<FILE>', type=argparse.FileType('w', encoding='UTF-8'), default=sys.stderr, help='output log file [stderr]')
+ parser.add_argument('-o', metavar='<FILE>', type=argparse.FileType(
+ 'w', encoding='UTF-8'), default=sys.stdout, help='output GEDCOM file [stdout]')
+ parser.add_argument('-l', metavar='<FILE>', type=argparse.FileType(
+ 'w', encoding='UTF-8'), default=sys.stderr, help='output log file [stderr]')
except TypeError:
sys.stderr.write('Python >= 3.4 is required to run this script\n')
- sys.stderr.write('(see https://docs.python.org/3/whatsnew/3.4.html#argparse)\n')
+ sys.stderr.write(
+ '(see https://docs.python.org/3/whatsnew/3.4.html#argparse)\n')
exit(2)
# extract arguments from the command line
exit(2)
username = args.u if args.u else input("Enter FamilySearch username: ")
- password = args.p if args.p else getpass.getpass("Enter FamilySearch password: ")
+ password = args.p if args.p else getpass.getpass(
+ "Enter FamilySearch password: ")
# initialize a FamilySearch session and a family tree object
fs = Session(username, password, args.v, args.l, args.t)
# check LDS account
if args.c:
- fs.get_url('https://familysearch.org/platform/tree/persons/%s/ordinances.json' % fs.get_userid())
+ fs.get_url(
+ 'https://familysearch.org/platform/tree/persons/%s/ordinances.json' % fs.get_userid())
loop = asyncio.get_event_loop()
todo = next_todo - done
# download ancestors
- loop.run_until_complete(download_tree(tree.add_parents, todo, args.a, loop))
+ loop.run_until_complete(download_tree(
+ tree.add_parents, todo, args.a, loop))
# download descendants
todo = set(tree.indi.keys())
- loop.run_until_complete(download_tree(tree.add_children, todo, args.d, loop))
+ loop.run_until_complete(download_tree(
+ tree.add_children, todo, args.d, loop))
# download spouses
async def download_spouses(loop):
futures = set()
for fid, indi in tree.indi.items():
if args.c:
- futures.add(loop.run_in_executor(None, tree.add_ordinances, fid))
+ futures.add(loop.run_in_executor(
+ None, tree.add_ordinances, fid))
futures.add(loop.run_in_executor(None, indi.get_notes))
if args.r:
futures.add(loop.run_in_executor(None, indi.get_contributors))
# compute number for family relationships and print GEDCOM file
tree.reset_num()
tree.print(args.o)
+
+ import pdb; pdb.set_trace()
\ No newline at end of file
import argparse
# local import
-from getmyancestors import Indi, Fam, Tree, Name, Note, Fact, Source, Ordinance, Memorie
+from getmyancestors import FACT_TAGS, Indi, Fam, Tree, Name, Note, Fact, Source, Ordinance, Memorie
sys.path.append(os.path.dirname(sys.argv[0]))
+FACT_TYPES = dict()
+
+for key, value in FACT_TAGS.items():
+ FACT_TYPES[value] = key
+
class Gedcom:
self.__get_name()
elif self.tag == 'SEX':
self.indi[self.num].gender = self.data
- elif self.tag == 'BIRT':
- self.__get_birt()
- elif self.tag == 'CHR':
- self.__get_chr()
- elif self.tag == 'DEAT':
- self.__get_deat()
- elif self.tag == 'BURI':
- self.__get_buri()
- elif self.tag == 'DSCR' or self.tag == 'OCCU' or self.tag == '_MILT':
- self.__get_fact()
+ elif self.tag in FACT_TYPES or self.tag == 'EVEN':
+ self.indi[self.num].facts.add(self.__get_fact())
elif self.tag == 'BAPL':
self.indi[self.num].baptism = self.__get_ordinance()
elif self.tag == 'CONL':
elif self.tag == 'SLGC':
self.indi[self.num].sealing_child = self.__get_ordinance()
elif self.tag == 'FAMS':
- self.indi[self.num].fams_num.add(int(self.data[2:len(self.data) - 1]))
+ self.indi[self.num].fams_num.add(
+ int(self.data[2:len(self.data) - 1]))
elif self.tag == 'FAMC':
- self.indi[self.num].famc_num.add(int(self.data[2:len(self.data) - 1]))
+ self.indi[self.num].famc_num.add(
+ int(self.data[2:len(self.data) - 1]))
elif self.tag == '_FSFTID':
self.indi[self.num].fid = self.data
elif self.tag == 'NOTE':
def __get_fam(self):
while self.__get_line() and self.level > 0:
if self.tag == 'HUSB':
- self.fam[self.num].husb_num = int(self.data[2:len(self.data) - 1])
+ self.fam[self.num].husb_num = int(
+ self.data[2:len(self.data) - 1])
elif self.tag == 'WIFE':
- self.fam[self.num].wife_num = int(self.data[2:len(self.data) - 1])
+ self.fam[self.num].wife_num = int(
+ self.data[2:len(self.data) - 1])
elif self.tag == 'CHIL':
- self.fam[self.num].chil_num.add(int(self.data[2:len(self.data) - 1]))
- elif self.tag in ('MARR', 'DIV', 'ANUL', '_COML'):
- self.fam[self.num].marriage_facts.add(self.__get_marr())
+ self.fam[self.num].chil_num.add(
+ int(self.data[2:len(self.data) - 1]))
+ elif self.tag in FACT_TYPES:
+ self.fam[self.num].facts.add(self.__get_fact())
elif self.tag == 'SLGS':
self.fam[self.num].sealing_spouse = self.__get_ordinance()
elif self.tag == '_FSFTID':
self.flag = True
def __get_deat(self):
- self.indi[self.num].living = False
while self.__get_line() and self.level > 1:
if self.tag == 'DATE':
self.indi[self.num].deatdate = self.data
self.indi[self.num].buriplac = self.data
self.flag = True
- def __get_marr(self):
- fact = Fact()
- if self.tag == 'MARR':
- fact.type = 'http://gedcomx.org/Marriage'
- elif self.tag == 'DIV':
- fact.type = 'http://gedcomx.org/Divorce'
- elif self.tag == 'ANUL':
- fact.type = 'http://gedcomx.org/Annulment'
- elif self.tag == '_COML':
- fact.type = 'http://gedcomx.org/CommonLawMarriage'
- while self.__get_line() and self.level > 1:
- if self.tag == 'DATE':
- fact.date = self.data
- elif self.tag == 'PLAC':
- fact.place = self.data
- elif self.tag == 'NOTE':
- num = int(self.data[2:len(self.data) - 1])
- if num not in self.note:
- self.note[num] = Note(tree=self.tree, num=num)
- fact.note = self.note[num]
- self.flag = True
- return fact
-
def __get_fact(self):
fact = Fact()
- fact.value = self.data
- if self.tag == 'DSCR':
- self.indi[self.num].physical_descriptions.add(fact)
- elif self.tag == 'OCCU':
- self.indi[self.num].occupations.add(fact)
- elif self.tag == '_MILT':
- self.indi[self.num].military.add(fact)
+ if self.tag == 'EVEN':
+ self.__get_line()
+ fact.type = 'data:,' + self.data
+ self.__get_line()
+ fact.value = self.data[12:]
+ else:
+ fact.type = FACT_TYPES[self.tag]
+ fact.value = self.data
while self.__get_line() and self.level > 1:
if self.tag == 'DATE':
fact.date = self.data
self.note[num] = Note(tree=self.tree, num=num)
fact.note = self.note[num]
self.flag = True
+ return fact
def __get_text(self):
text = self.data
def __get_memorie(self):
memorie = Memorie()
- pdb = False
while self.__get_line() and self.level > 1:
if self.tag == 'TITL':
memorie.description = self.__get_text()
self.fam[num].chil_fid.add(self.indi[chil].fid)
for num in self.indi:
for famc in self.indi[num].famc_num:
- self.indi[num].famc_fid.add((self.fam[famc].husb_fid, self.fam[famc].wife_fid))
+ self.indi[num].famc_fid.add(
+ (self.fam[famc].husb_fid, self.fam[famc].wife_fid))
for fams in self.indi[num].fams_num:
- self.indi[num].fams_fid.add((self.fam[fams].husb_fid, self.fam[fams].wife_fid))
+ self.indi[num].fams_fid.add(
+ (self.fam[fams].husb_fid, self.fam[fams].wife_fid))
if __name__ == '__main__':
- parser = argparse.ArgumentParser(description='Merge GEDCOM data from FamilySearch Tree (4 Jul 2016)', add_help=False, usage='mergemyancestors.py -i input1.ged input2.ged ... [options]')
+ parser = argparse.ArgumentParser(description='Merge GEDCOM data from FamilySearch Tree (4 Jul 2016)',
+ add_help=False, usage='mergemyancestors.py -i input1.ged input2.ged ... [options]')
try:
- parser.add_argument('-i', metavar='<FILE>', nargs='+', type=argparse.FileType('r', encoding='UTF-8'), default=sys.stdin, help='input GEDCOM files [stdin]')
- parser.add_argument('-o', metavar='<FILE>', nargs='?', type=argparse.FileType('w', encoding='UTF-8'), default=sys.stdout, help='output GEDCOM files [stdout]')
+ parser.add_argument('-i', metavar='<FILE>', nargs='+', type=argparse.FileType(
+ 'r', encoding='UTF-8'), default=sys.stdin, help='input GEDCOM files [stdin]')
+ parser.add_argument('-o', metavar='<FILE>', nargs='?', type=argparse.FileType(
+ 'w', encoding='UTF-8'), default=sys.stdout, help='output GEDCOM files [stdout]')
except TypeError:
sys.stderr.write('Python >= 3.4 is required to run this script\n')
- sys.stderr.write('(see https://docs.python.org/3/whatsnew/3.4.html#argparse)\n')
+ sys.stderr.write(
+ '(see https://docs.python.org/3/whatsnew/3.4.html#argparse)\n')
exit(2)
# extract arguments from the command line
tree.indi[fid] = Indi(tree=tree, num=indi_counter)
tree.indi[fid].tree = tree
tree.indi[fid].fid = ged.indi[num].fid
- tree.indi[fid].living = ged.indi[num].living
tree.indi[fid].fams_fid |= ged.indi[num].fams_fid
tree.indi[fid].famc_fid |= ged.indi[num].famc_fid
tree.indi[fid].name = ged.indi[num].name
tree.indi[fid].aka = ged.indi[num].aka
tree.indi[fid].married = ged.indi[num].married
tree.indi[fid].gender = ged.indi[num].gender
- tree.indi[fid].birtdate = ged.indi[num].birtdate
- tree.indi[fid].birtplac = ged.indi[num].birtplac
- tree.indi[fid].chrdate = ged.indi[num].chrdate
- tree.indi[fid].chrplac = ged.indi[num].chrplac
- tree.indi[fid].deatdate = ged.indi[num].deatdate
- tree.indi[fid].deatplac = ged.indi[num].deatplac
- tree.indi[fid].buridate = ged.indi[num].buridate
- tree.indi[fid].buriplac = ged.indi[num].buriplac
- tree.indi[fid].physical_descriptions = ged.indi[num].physical_descriptions
- tree.indi[fid].occupations = ged.indi[num].occupations
- tree.indi[fid].military = ged.indi[num].military
+ tree.indi[fid].facts = ged.indi[num].facts
tree.indi[fid].notes = ged.indi[num].notes
tree.indi[fid].sources = ged.indi[num].sources
tree.indi[fid].memories = ged.indi[num].memories
tree.fam[(husb, wife)].tree = tree
tree.fam[(husb, wife)].chil_fid |= ged.fam[num].chil_fid
tree.fam[(husb, wife)].fid = ged.fam[num].fid
- tree.fam[(husb, wife)].marriage_facts = ged.fam[num].marriage_facts
+ tree.fam[(husb, wife)].facts = ged.fam[num].facts
tree.fam[(husb, wife)].notes = ged.fam[num].notes
tree.fam[(husb, wife)].sources = ged.fam[num].sources
tree.fam[(husb, wife)].sealing_spouse = ged.fam[num].sealing_spouse