import time
import asyncio
import tempfile
-from tkinter import Tk, StringVar, IntVar, filedialog, messagebox, Menu, TclError, PhotoImage
+from tkinter import (
+ Tk,
+ StringVar,
+ IntVar,
+ filedialog,
+ messagebox,
+ Menu,
+ TclError,
+ PhotoImage,
+)
from tkinter.ttk import Frame, Label, Entry, Button, Checkbutton, Treeview, Notebook
from threading import Thread
from diskcache import Cache
# local import
-from getmyancestors import Session, Tree, Indi, Fam
-from mergemyancestors import Gedcom
-from translation import translations
+from getmyancestors.getmyancestors import Session, Tree, Indi, Fam
+from getmyancestors.mergemyancestors import Gedcom
+from getmyancestors.translation import translations
tmp_dir = os.path.join(tempfile.gettempdir(), "fstogedcom")
""" Entry widget with right-clic menu to copy/cut/paste """
def __init__(self, master, **kw):
- super(EntryWithMenu, self).__init__(master, **kw)
+ super().__init__(master, **kw)
self.bind("<Button-3>", self.click_right)
def click_right(self, event):
""" List of GEDCOM files to merge """
def __init__(self, master, **kwargs):
- super(FilesToMerge, self).__init__(master, selectmode="extended", height=5, **kwargs)
+ super().__init__(master, selectmode="extended", height=5, **kwargs)
self.heading("#0", text=_("Files"))
self.column("#0", width=300)
self.files = dict()
""" add a GEDCOM file """
if any(f.name == filename for f in self.files.values()):
messagebox.showinfo(
- _("Error"), message=_("File already exist: ") + os.path.basename(filename)
+ _("Error"),
+ message=_("File already exist: ") + os.path.basename(filename),
)
return
if not os.path.exists(filename):
""" Merge GEDCOM widget """
def __init__(self, master, **kwargs):
- super(Merge, self).__init__(master, **kwargs)
+ super().__init__(master, **kwargs)
warning = Label(
self,
font=("a", 7),
tree.indi[fid].baptism = ged.indi[num].baptism
tree.indi[fid].confirmation = ged.indi[num].confirmation
tree.indi[fid].endowment = ged.indi[num].endowment
- if not (tree.indi[fid].sealing_child and tree.indi[fid].sealing_child.famc):
+ if not (
+ tree.indi[fid].sealing_child and tree.indi[fid].sealing_child.famc
+ ):
tree.indi[fid].sealing_child = ged.indi[num].sealing_child
# add informations about families
def quit(self):
""" prevent exception on quit during download """
- super(Merge, self).quit()
+ super().quit()
os._exit(1)
""" Sign In widget """
def __init__(self, master, **kwargs):
- super(SignIn, self).__init__(master, **kwargs)
+ super().__init__(master, **kwargs)
self.username = StringVar()
self.username.set(cache.get("username") or "")
self.password = StringVar()
label_username = Label(self, text=_("Username:"))
entry_username = EntryWithMenu(self, textvariable=self.username, width=30)
label_password = Label(self, text=_("Password:"))
- entry_password = EntryWithMenu(self, show="●", textvariable=self.password, width=30)
+ entry_password = EntryWithMenu(
+ self, show="●", textvariable=self.password, width=30
+ )
label_username.grid(row=0, column=0, pady=15, padx=(0, 5))
entry_username.grid(row=0, column=1)
label_password.grid(row=1, column=0, padx=(0, 5))
""" List of starting individuals """
def __init__(self, master, **kwargs):
- super(StartIndis, self).__init__(
+ super().__init__(
master, selectmode="extended", height=5, columns=("fid",), **kwargs
)
self.heading("#0", text=_("Name"))
messagebox.showinfo(_("Error"), message=_("ID already exist"))
return None
if not re.match(r"[A-Z0-9]{4}-[A-Z0-9]{3}", fid):
- messagebox.showinfo(_("Error"), message=_("Invalid FamilySearch ID: ") + fid)
+ messagebox.showinfo(
+ _("Error"), message=_("Invalid FamilySearch ID: ") + fid
+ )
return None
fs = self.master.master.master.fs
data = fs.get_url("/platform/tree/persons/%s" % fid)
for name in data["persons"][0]["names"]:
if name["preferred"]:
self.indis[
- self.insert("", 0, text=name["nameForms"][0]["fullText"], values=fid)
+ self.insert(
+ "", 0, text=name["nameForms"][0]["fullText"], values=fid
+ )
] = fid
return True
messagebox.showinfo(_("Error"), message=_("Individual not found"))
""" Options form """
def __init__(self, master, ordinances=False, **kwargs):
- super(Options, self).__init__(master, **kwargs)
+ super().__init__(master, **kwargs)
self.ancestors = IntVar()
self.ancestors.set(4)
self.descendants = IntVar()
entry_ancestors = EntryWithMenu(self, textvariable=self.ancestors, width=5)
label_descendants = Label(self, text=_("Number of generations to descend"))
entry_descendants = EntryWithMenu(self, textvariable=self.descendants, width=5)
- btn_add_indi = Button(btn, text=_("Add a FamilySearch ID"), command=self.add_indi)
+ btn_add_indi = Button(
+ btn, text=_("Add a FamilySearch ID"), command=self.add_indi
+ )
btn_spouses = Checkbutton(
- self, text="\t" + _("Add spouses and couples information"), variable=self.spouses
+ self,
+ text="\t" + _("Add spouses and couples information"),
+ variable=self.spouses,
)
btn_ordinances = Checkbutton(
self, text="\t" + _("Add Temple information"), variable=self.ordinances
)
btn_contributors = Checkbutton(
- self, text="\t" + _("Add list of contributors in notes"), variable=self.contributors
+ self,
+ text="\t" + _("Add list of contributors in notes"),
+ variable=self.contributors,
)
self.start_indis.grid(row=0, column=0, columnspan=3)
entry_fid.grid(row=0, column=0, sticky="w")
""" Main widget """
def __init__(self, master, **kwargs):
- super(Download, self).__init__(master, borderwidth=20, **kwargs)
+ super().__init__(master, borderwidth=20, **kwargs)
self.fs = None
self.tree = None
self.logfile = None
self.start_time = None
info = Frame(self, borderwidth=10)
self.info_label = Label(
- info, wraplength=350, borderwidth=20, justify="center", font=("a", 10, "bold")
+ info,
+ wraplength=350,
+ borderwidth=20,
+ justify="center",
+ font=("a", 10, "bold"),
)
self.info_indis = Label(info)
self.info_fams = Label(info)
self.form = Frame(self)
self.sign_in = SignIn(self.form)
self.options = None
- self.title = Label(self, text=_("Sign In to FamilySearch"), font=("a", 12, "bold"))
+ self.title = Label(
+ self, text=_("Sign In to FamilySearch"), font=("a", 12, "bold")
+ )
buttons = Frame(self)
- self.btn_quit = Button(buttons, text=_("Quit"), command=Thread(target=self.quit).start)
+ self.btn_quit = Button(
+ buttons, text=_("Quit"), command=Thread(target=self.quit).start
+ )
self.btn_valid = Button(
buttons, text=_("Sign In"), command=self.command_in_thread(self.login)
)
username = self.sign_in.username.get()
password = self.sign_in.password.get()
if not (username and password):
- messagebox.showinfo(message=_("Please enter your FamilySearch username and password."))
+ messagebox.showinfo(
+ message=_("Please enter your FamilySearch username and password.")
+ )
return
self.btn_valid.config(state="disabled")
self.info(_("Login to FamilySearch..."))
timeout=1,
)
if not self.fs.logged:
- messagebox.showinfo(_("Error"), message=_("The username or password was incorrect"))
+ messagebox.showinfo(
+ _("Error"), message=_("The username or password was incorrect")
+ )
self.btn_valid.config(state="normal")
self.info("")
return
self.options.pack()
self.master.change_lang()
self.btn_valid.config(
- command=self.command_in_thread(self.download), state="normal", text=_("Download")
+ command=self.command_in_thread(self.download),
+ state="normal",
+ text=_("Download"),
)
self.options.start_indis.add_indi(self.fs.fid)
self.update_needed = False
self.update_needed = False
if self.logfile:
self.logfile.close()
- super(Download, self).quit()
+ super().quit()
os._exit(1)
def download(self):
""" download family tree """
todo = [
- self.options.start_indis.indis[key] for key in sorted(self.options.start_indis.indis)
+ self.options.start_indis.indis[key]
+ for key in sorted(self.options.start_indis.indis)
]
for fid in todo:
if not re.match(r"[A-Z0-9]{4}-[A-Z0-9]{3}", fid):
- messagebox.showinfo(_("Error"), message=_("Invalid FamilySearch ID: ") + fid)
+ messagebox.showinfo(
+ _("Error"), message=_("Invalid FamilySearch ID: ") + fid
+ )
return
self.start_time = time.time()
self.options.destroy()
for fid, indi in self.tree.indi.items():
futures.add(loop.run_in_executor(None, indi.get_notes))
if ordi:
- futures.add(loop.run_in_executor(None, self.tree.add_ordinances, fid))
+ futures.add(
+ loop.run_in_executor(None, self.tree.add_ordinances, fid)
+ )
if cont:
futures.add(loop.run_in_executor(None, indi.get_contributors))
for fam in self.tree.fam.values():
t = round(time.time() - self.start_time)
minutes = t // 60
seconds = t % 60
- self.time.config(text=_("Elapsed time: %s:%s") % (minutes, str(seconds).zfill(2)))
+ self.time.config(
+ text=_("Elapsed time: %s:%s") % (minutes, str(seconds).zfill(2))
+ )
def update_gui(self):
""" update widget """
""" Main notebook """
def __init__(self, master, **kwargs):
- super(FStoGEDCOM, self).__init__(master, width=400, **kwargs)
+ super().__init__(master, width=400, **kwargs)
self.download = Download(self)
self.merge = Merge(self)
self.add(self.download, text=_("Download GEDCOM"))
self.merge.btn_add_file.config(text=_("Add files"))
-if __name__ == "__main__":
+def main():
root = Tk()
root.title("FamilySearch to GEDCOM")
if sys.platform != "darwin":
- root.iconphoto(True, PhotoImage(file="fstogedcom.png"))
+ root.iconphoto(
+ True,
+ PhotoImage(file=os.path.join(os.path.dirname(__file__), "fstogedcom.png")),
+ )
fstogedcom = FStoGEDCOM(root)
fstogedcom.mainloop()
+
+
+if __name__ == "__main__":
+ main()
-#!/usr/bin/env python3
# coding: utf-8
-"""
- getmyancestors.py - Retrieve GEDCOM data from FamilySearch Tree
- Copyright (C) 2014-2016 Giulio Genovese (giulio.genovese@gmail.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 3 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, see <http://www.gnu.org/licenses/>.
-
- Written by Giulio Genovese <giulio.genovese@gmail.com>
- and by Benoît Fontaine <benoitfontaine.ba@gmail.com>
-"""
# global import
from __future__ import print_function
import babelfish
# local import
-from translation import translations
-
+import getmyancestors
+from getmyancestors.translation import translations
# is subject to change: see https://www.familysearch.org/developers/docs/api/tree/Persons_resource
MAX_PERSONS = 200
class Session:
- """ Create a FamilySearch session
- :param username and password: valid FamilySearch credentials
- :param verbose: True to active verbose mode
- :param logfile: a file object or similar
- :param timeout: time before retry a request
+ """Create a FamilySearch session
+ :param username and password: valid FamilySearch credentials
+ :param verbose: True to active verbose mode
+ :param logfile: a file object or similar
+ :param timeout: time before retry a request
"""
def __init__(self, username, password, verbose=False, logfile=False, timeout=60):
self.logfile.write(log)
def login(self):
- """ retrieve FamilySearch session ID
- (https://familysearch.org/developers/docs/guides/oauth2)
+ """retrieve FamilySearch session ID
+ (https://familysearch.org/developers/docs/guides/oauth2)
"""
while True:
try:
self.write_log("Downloading: " + url)
r = requests.post(
url,
- data={"params": params, "userName": self.username, "password": self.password},
+ data={
+ "params": params,
+ "userName": self.username,
+ "password": self.password,
+ },
allow_redirects=False,
)
if r.status_code == 403:
if (
"message" in r.json()["errors"][0]
- and r.json()["errors"][0]["message"] == "Unable to get ordinances."
+ and r.json()["errors"][0]["message"]
+ == "Unable to get ordinances."
):
self.write_log(
"Unable to get ordinances. "
self.display_name = data["users"][0]["displayName"]
def _(self, string):
- """ translate a string into user's language
- TODO replace translation file for gettext format
+ """translate a string into user's language
+ TODO replace translation file for gettext format
"""
if string in translations and self.lang in translations[string]:
return translations[string][self.lang]
class Note:
- """ GEDCOM Note class
- :param text: the Note content
- :param tree: a Tree object
- :param num: the GEDCOM identifier
+ """GEDCOM Note class
+ :param text: the Note content
+ :param tree: a Tree object
+ :param num: the GEDCOM identifier
"""
counter = 0
class Source:
- """ GEDCOM Source class
- :param data: FS Source data
- :param tree: a Tree object
- :param num: the GEDCOM identifier
+ """GEDCOM Source class
+ :param data: FS Source data
+ :param tree: a Tree object
+ :param num: the GEDCOM identifier
"""
counter = 0
class Fact:
- """ GEDCOM Fact class
- :param data: FS Fact data
- :param tree: a tree object
+ """GEDCOM Fact class
+ :param data: FS Fact data
+ :param tree: a tree object
"""
def __init__(self, data=None, tree=None):
self.map = tree.places[place["description"][1:]]
if "changeMessage" in data["attribution"]:
self.note = Note(data["attribution"]["changeMessage"], tree)
- if self.type == "http://gedcomx.org/Death" and not (self.date or self.place):
+ if self.type == "http://gedcomx.org/Death" and not (
+ self.date or self.place
+ ):
self.value = "Y"
def print(self, file=sys.stdout):
- """ print Fact in GEDCOM format
- the GEDCOM TAG depends on the type, defined in FACT_TAGS
+ """print Fact in GEDCOM format
+ the GEDCOM TAG depends on the type, defined in FACT_TAGS
"""
if self.type in FACT_TAGS:
tmp = "1 " + FACT_TAGS[self.type]
class Memorie:
- """ GEDCOM Memorie class
- :param data: FS Memorie data
+ """GEDCOM Memorie class
+ :param data: FS Memorie data
"""
def __init__(self, data=None):
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 = (
+ "" if not self.description else self.description + "\n"
+ ) + data["descriptions"][0]["value"]
def print(self, file=sys.stdout):
""" print Memorie in GEDCOM format """
class Name:
- """ GEDCOM Name class
- :param data: FS Name data
- :param tree: a Tree object
+ """GEDCOM Name class
+ :param data: FS Name data
+ :param tree: a Tree object
"""
def __init__(self, data=None, tree=None):
self.note = Note(data["attribution"]["changeMessage"], tree)
def print(self, file=sys.stdout, typ=None):
- """ print Name in GEDCOM format
- :param typ: type for additional names
+ """print Name in GEDCOM format
+ :param typ: type for additional names
"""
tmp = "1 NAME %s /%s/" % (self.given, self.surname)
if self.suffix:
class Ordinance:
- """ GEDCOM Ordinance class
- :param data: FS Ordinance data
+ """GEDCOM Ordinance class
+ :param data: FS Ordinance data
"""
def __init__(self, data=None):
class Indi:
- """ GEDCOM individual class
- :param fid' FamilySearch id
- :param tree: a tree object
- :param num: the GEDCOM identifier
+ """GEDCOM individual class
+ :param fid' FamilySearch id
+ :param tree: a tree object
+ :param num: the GEDCOM identifier
"""
counter = 0
else:
self.facts.add(Fact(x, self.tree))
if "sources" in data:
- sources = self.tree.fs.get_url("/platform/tree/persons/%s/sources" % self.fid)
+ sources = self.tree.fs.get_url(
+ "/platform/tree/persons/%s/sources" % self.fid
+ )
if sources:
quotes = dict()
for quote in sources["persons"][0]["sources"]:
for source in sources["sourceDescriptions"]:
if source["id"] not in self.tree.sources:
self.tree.sources[source["id"]] = Source(source, self.tree)
- self.sources.add((self.tree.sources[source["id"]], quotes[source["id"]]))
+ self.sources.add(
+ (self.tree.sources[source["id"]], quotes[source["id"]])
+ )
if "evidence" in data:
url = "/platform/tree/persons/%s/memories" % self.fid
memorie = self.tree.fs.get_url(url)
if x["mediaType"] == "text/plain":
text = "\n".join(
val.get("value", "")
- for val in x.get("titles", []) + x.get("descriptions", [])
+ for val in x.get("titles", [])
+ + x.get("descriptions", [])
)
self.notes.add(Note(text, self.tree))
else:
self.notes.add(Note(text_note, self.tree))
def get_ordinances(self):
- """ retrieve LDS ordinances
- need a LDS account
+ """retrieve LDS ordinances
+ need a LDS account
"""
res = []
famc = False
for contributors in entries["contributors"]:
temp.add(contributors["name"])
if temp:
- text = "=== %s ===\n%s" % (self.tree.fs._("Contributors"), "\n".join(sorted(temp)))
+ text = "=== %s ===\n%s" % (
+ self.tree.fs._("Contributors"),
+ "\n".join(sorted(temp)),
+ )
for n in self.tree.notes:
if n.text == text:
self.notes.add(n)
class Fam:
- """ GEDCOM family class
- :param husb: husbant fid
- :param wife: wife fid
- :param tree: a Tree object
- :param num: a GEDCOM identifier
+ """GEDCOM family class
+ :param husb: husbant fid
+ :param wife: wife fid
+ :param tree: a Tree object
+ :param num: a GEDCOM identifier
"""
counter = 0
self.chil_fid.add(child)
def add_marriage(self, fid):
- """ retrieve and add marriage information
- :param fid: the marriage fid
+ """retrieve and add marriage information
+ :param fid: the marriage fid
"""
if not self.fid:
self.fid = fid
source["id"] in new_sources
and source["id"] not in self.tree.sources
):
- self.tree.sources[source["id"]] = Source(source, self.tree)
+ self.tree.sources[source["id"]] = Source(
+ source, self.tree
+ )
for source_fid in quotes:
- self.sources.add((self.tree.sources[source_fid], quotes[source_fid]))
+ self.sources.add(
+ (self.tree.sources[source_fid], quotes[source_fid])
+ )
def get_notes(self):
""" retrieve marriage notes """
if self.fid:
- notes = self.tree.fs.get_url("/platform/tree/couple-relationships/%s/notes" % self.fid)
+ notes = self.tree.fs.get_url(
+ "/platform/tree/couple-relationships/%s/notes" % self.fid
+ )
if notes:
for n in notes["relationships"][0]["notes"]:
text_note = "=== %s ===\n" % n["subject"] if "subject" in n else ""
if self.fid:
temp = set()
url = "/platform/tree/couple-relationships/%s/changes" % self.fid
- data = self.tree.fs.get_url(url, {"Accept": "application/x-gedcomx-atom+json"})
+ data = self.tree.fs.get_url(
+ url, {"Accept": "application/x-gedcomx-atom+json"}
+ )
if data:
for entries in data["entries"]:
for contributors in entries["contributors"]:
temp.add(contributors["name"])
if temp:
- text = "=== %s ===\n%s" % (self.tree.fs._("Contributors"), "\n".join(sorted(temp)))
+ text = "=== %s ===\n%s" % (
+ self.tree.fs._("Contributors"),
+ "\n".join(sorted(temp)),
+ )
for n in self.tree.notes:
if n.text == text:
self.notes.add(n)
class Tree:
- """ family tree class
- :param fs: a Session object
+ """family tree class
+ :param fs: a Session object
"""
def __init__(self, fs=None):
self.lang = babelfish.Language.fromalpha2(fs.lang).name
def add_indis(self, fids):
- """ add individuals to the family tree
- :param fids: an iterable of fid
+ """add individuals to the family tree
+ :param fids: an iterable of fid
"""
async def add_datas(loop, data):
futures = set()
for person in data["persons"]:
self.indi[person["id"]] = Indi(person["id"], self)
- futures.add(loop.run_in_executor(None, self.indi[person["id"]].add_data, person))
+ futures.add(
+ loop.run_in_executor(None, self.indi[person["id"]].add_data, person)
+ )
for future in futures:
await future
loop.run_until_complete(add_datas(loop, data))
if "childAndParentsRelationships" in data:
for rel in data["childAndParentsRelationships"]:
- father = rel["parent1"]["resourceId"] if "parent1" in rel else None
- mother = rel["parent2"]["resourceId"] if "parent2" in rel else None
+ father = (
+ rel["parent1"]["resourceId"] if "parent1" in rel else None
+ )
+ mother = (
+ rel["parent2"]["resourceId"] if "parent2" in rel else None
+ )
child = rel["child"]["resourceId"] if "child" in rel else None
if child in self.indi:
self.indi[child].parents.add((father, mother))
person2 = rel["person2"]["resourceId"]
relfid = rel["id"]
if person1 in self.indi:
- self.indi[person1].spouses.add((person1, person2, relfid))
+ self.indi[person1].spouses.add(
+ (person1, person2, relfid)
+ )
if person2 in self.indi:
- self.indi[person2].spouses.add((person1, person2, relfid))
+ self.indi[person2].spouses.add(
+ (person1, person2, relfid)
+ )
new_fids = new_fids[MAX_PERSONS:]
def add_fam(self, father, mother):
- """ add a family to the family tree
- :param father: the father fid or None
- :param mother: the mother fid or None
+ """add a family to the family tree
+ :param father: the father fid or None
+ :param mother: the mother fid or None
"""
if (father, mother) not in self.fam:
self.fam[(father, mother)] = Fam(father, mother, self)
def add_trio(self, father, mother, child):
- """ add a children relationship to the family tree
- :param father: the father fid or None
- :param mother: the mother fid or None
- :param child: the child fid or None
+ """add a children relationship to the family tree
+ :param father: the father fid or None
+ :param mother: the mother fid or None
+ :param child: the child fid or None
"""
if father in self.indi:
self.indi[father].add_fams((father, mother))
self.fam[(father, mother)].add_child(child)
def add_parents(self, fids):
- """ add parents relationships
- :param fids: a set of fids
+ """add parents relationships
+ :param fids: a set of fids
"""
parents = set()
for fid in fids & self.indi.keys():
return set(filter(None, parents))
def add_spouses(self, fids):
- """ add spouse relationships
- :param fids: a set of fid
+ """add spouse relationships
+ :param fids: a set of fid
"""
async def add(loop, rels):
for father, mother, relfid in rels:
if (father, mother) in self.fam:
futures.add(
- loop.run_in_executor(None, self.fam[(father, mother)].add_marriage, relfid)
+ loop.run_in_executor(
+ None, self.fam[(father, mother)].add_marriage, relfid
+ )
)
for future in futures:
await future
rels |= self.indi[fid].spouses
loop = asyncio.get_event_loop()
if rels:
- self.add_indis(set.union(*({father, mother} for father, mother, relfid in rels)))
+ self.add_indis(
+ set.union(*({father, mother} for father, mother, relfid in rels))
+ )
for father, mother, _ in rels:
if father in self.indi and mother in self.indi:
self.indi[father].add_fams((father, mother))
loop.run_until_complete(add(loop, rels))
def add_children(self, fids):
- """ add children relationships
- :param fids: a set of fid
+ """add children relationships
+ :param fids: a set of fid
"""
rels = set()
for fid in fids & self.indi.keys():
return children
def add_ordinances(self, fid):
- """ retrieve ordinances
- :param fid: an individual fid
+ """retrieve ordinances
+ :param fid: an individual fid
"""
if fid in self.indi:
ret, famc = self.indi[fid].get_ordinances()
file.write("0 HEAD\n")
file.write("1 CHAR UTF-8\n")
file.write("1 GEDC\n")
- file.write("2 VERS 5.5.1\n")
+ file.write("2 VERS 5.1.1\n")
file.write("2 FORM LINEAGE-LINKED\n")
file.write("1 SOUR getmyancestors\n")
- file.write("2 VERS 1.0\n")
+ file.write("2 VERS %s\n" % getmyancestors.__version__)
file.write("2 NAME getmyancestors\n")
file.write("1 DATE %s\n" % time.strftime("%d %b %Y"))
file.write("2 TIME %s\n" % time.strftime("%H:%M:%S"))
parser = argparse.ArgumentParser(
description="Retrieve GEDCOM data from FamilySearch Tree (4 Jul 2016)",
add_help=False,
- usage="getmyancestors.py -u username -p password [options]",
+ usage="getmyancestors -u username -p password [options]",
+ )
+ parser.add_argument(
+ "-u", "--username", metavar="<STR>", type=str, help="FamilySearch username"
+ )
+ parser.add_argument(
+ "-p", "--password", metavar="<STR>", type=str, help="FamilySearch password"
)
- parser.add_argument("-u", "--username", metavar="<STR>", type=str, help="FamilySearch username")
- parser.add_argument("-p", "--password", metavar="<STR>", type=str, help="FamilySearch password")
parser.add_argument(
"-i",
"--individuals",
help="Increase output verbosity [False]",
)
parser.add_argument(
- "-t", "--timeout", metavar="<INT>", type=int, default=60, help="Timeout in seconds [60]"
+ "-t",
+ "--timeout",
+ metavar="<INT>",
+ type=int,
+ default=60,
+ help="Timeout in seconds [60]",
)
parser.add_argument(
"--show-password",
default=False,
help="Show password in .settings file [False]",
)
+ parser.add_argument(
+ "--save-settings",
+ action="store_true",
+ default=False,
+ help="Save settings into file [False]",
+ )
try:
parser.add_argument(
"-o",
if not re.match(r"[A-Z0-9]{4}-[A-Z0-9]{3}", fid):
sys.exit("Invalid FamilySearch ID: " + fid)
- args.username = args.username if args.username else input("Enter FamilySearch username: ")
+ args.username = (
+ args.username if args.username else input("Enter FamilySearch username: ")
+ )
args.password = (
- args.password if args.password else getpass.getpass("Enter FamilySearch password: ")
+ args.password
+ if args.password
+ else getpass.getpass("Enter FamilySearch password: ")
)
time_count = time.time()
- # Report settings used when getmyancestors.py is executed.
- if args.outfile.name != "<stdout>":
+ # Report settings used when getmyancestors is executed.
+ if args.save_settings and args.outfile.name != "<stdout>":
def parse_action(act):
if not args.show_password and act.dest == "password":
settings_name = args.outfile.name.split(".")[0] + ".settings"
try:
with open(settings_name, "w") as settings_file:
- settings_file.write(formatting.format("time stamp: ", time.strftime("%X %x %Z")))
+ settings_file.write(
+ formatting.format("time stamp: ", time.strftime("%X %x %Z"))
+ )
for action in parser._actions:
settings_file.write(
- formatting.format(action.option_strings[-1], parse_action(action))
+ formatting.format(
+ action.option_strings[-1], parse_action(action)
+ )
)
except OSError as exc:
- print("Unable to write %s: %s" % (settings_name, repr(exc)), file=sys.stderr)
+ print(
+ "Unable to write %s: %s" % (settings_name, repr(exc)), file=sys.stderr
+ )
# initialize a FamilySearch session and a family tree object
print("Login to FamilySearch...", file=sys.stderr)
# check LDS account
if args.get_ordinances:
- test = fs.get_url("/service/tree/tree-data/reservations/person/%s/ordinances" % fs.fid, {})
+ test = fs.get_url(
+ "/service/tree/tree-data/reservations/person/%s/ordinances" % fs.fid, {}
+ )
if test["status"] != "OK":
sys.exit(2)
if not todo:
break
done |= todo
- print(_("Downloading %s. of generations of ancestors...") % (i + 1),
- file=sys.stderr)
+ print(
+ _("Downloading %s. of generations of ancestors...") % (i + 1),
+ file=sys.stderr,
+ )
todo = tree.add_parents(todo) - done
# download descendants
if not todo:
break
done |= todo
- print(_("Downloading %s. of generations of descendants...") %
- (i + 1), file=sys.stderr)
+ print(
+ _("Downloading %s. of generations of descendants...") % (i + 1),
+ file=sys.stderr,
+ )
todo = tree.add_children(todo) - done
# download spouses
if args.marriage:
- print(_("Downloading spouses and marriage information..."),
- file=sys.stderr)
+ print(_("Downloading spouses and marriage information..."), file=sys.stderr)
todo = set(tree.indi.keys())
tree.add_spouses(todo)
)
+ (_(" and contributors") if args.get_contributors else "")
+ "...",
- file=sys.stderr
+ file=sys.stderr,
)
loop.run_until_complete(download_stuff(loop))
str(round(time.time() - time_count)),
str(fs.counter),
),
- file=sys.stderr
+ file=sys.stderr,
)