diff --git a/install.py b/install.py index 307696c..7e71ccb 100644 --- a/install.py +++ b/install.py @@ -26,6 +26,27 @@ except ImportError: stdout=subprocess.PIPE, stderr=subprocess.PIPE) print(p.communicate()) -url = "https://git.roflcopter.fr/sdjgeek/purge-registres-deces-insee/-/archive/v5.0/purge-registres-deces-insee-v5.0.zip" -myfile = requests.get(url) -open('purge-registres-deces-insee-v5.0.zip', 'wb').write(myfile.content) +try: + import pandas +except ImportError: + print("Installing pandas") + p = subprocess.Popen([sys.executable, "-m", "pip", "install", "-U", "pandas"], + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + print(p.communicate()) + +try: + import xlrd +except ImportError: + print("Installing xlrd") + p = subprocess.Popen([sys.executable, "-m", "pip", "install", "-U", "xlrd"], + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + print(p.communicate()) + +try: + import numpy +except ImportError: + print("Installing numpy") + p = subprocess.Popen([sys.executable, "-m", "pip", "install", "-U", "numpy"], + stdout=subprocess.PIPE, stderr=subprocess.PIPE) + print(p.communicate()) + diff --git a/purge-registres-deces-insee/excel_in.py b/purge-registres-deces-insee/excel_in.py index a5dfadf..bc54af6 100644 --- a/purge-registres-deces-insee/excel_in.py +++ b/purge-registres-deces-insee/excel_in.py @@ -8,6 +8,7 @@ Classe d'accès aux données du site de l'Église import os import pandas as pd +import numpy as np from membre_base import MembreBase, MembreProvider @@ -25,12 +26,23 @@ class ExcelIn(MembreProvider): def __init__(self, provider, row): super().__init__(provider) + self.r_id = str(row["id"]) + self.r_first_name = str(row["first_name"]).strip().split(' ')[0].upper() + self.r_last_name = str(row["last_name"]).strip().split(' ')[0].upper() + self.r_maiden_name = str(row["maiden_name"]).strip().split(' ')[0].upper() if type(row["maiden_name"]) == np.str else None + self.r_annee = str(row["annee"]) + self.r_mois = str(row["mois"]) + self.r_jour = str(row["jour"]) + self.r_ville = "" + self.r_sexe = "F" if str(row["status"]) == "Female" else "M" def get_name(self): return os.path.basename(self.excel_path) def load(self): - self.dataframe = pd.read_excel(self.excel_path) + self.dataframe = pd.read_excel(self.excel_path, skiprows=[0, 1], usecols="B:E,G:I,K", header=None, + names=["last_name", "first_name", "maiden_name", "id", "jour", "mois", "annee", + "status"]) return len(self.dataframe) def get_member_list(self): diff --git a/purge-registres-deces-insee/excel_out.py b/purge-registres-deces-insee/excel_out.py new file mode 100644 index 0000000..60bd01d --- /dev/null +++ b/purge-registres-deces-insee/excel_out.py @@ -0,0 +1,30 @@ +""" +Copyright (c) 2020 Sdj Geek +Voir le fichier LICENSE + +Classe d'accès aux données INSEE dans la base SQLite + +""" + +import pandas as pd + + +class ExcelOut: + + def __init__(self, out_path): + self.out_path = out_path + self.data = list() + + def add_member(self, member): + self.data.append({ + 'nom_registres': member.get_nom_registres(), + 'nom_insee': member.get_nom_insee(), + 'mrn': member.r_id, + 'death_year': member.i_annee_deces, + 'death_month': member.i_mois_deces, + 'death_day': member.i_jour_deces + }) + + def generate_output(self): + df = pd.DataFrame(self.data) + df.to_excel(self.out_path) diff --git a/purge-registres-deces-insee/gui_trouver_decedes.py b/purge-registres-deces-insee/gui_trouver_decedes.py index 5832ae6..0e4fd54 100644 --- a/purge-registres-deces-insee/gui_trouver_decedes.py +++ b/purge-registres-deces-insee/gui_trouver_decedes.py @@ -37,38 +37,50 @@ class MainApplication(tk.Frame): self.entry_bdd_insee.grid(row=0, column=1, sticky='ew') self.button_bdd_insee = tk.Button(self.frame, text="...", command=self.command_button_bdd_insee) self.button_bdd_insee.grid(row=0, column=2, sticky='w') + + # Sélection fichier Excel + self.label_fichier_excel = tk.Label(self.frame, text="Fichier Excel") + self.label_fichier_excel.grid(row=1, column=0, sticky='e') + self.value_fichier_excel = tk.StringVar() + self.entry_fichier_excel = tk.Entry(self.frame, state='disabled', textvariable=self.value_fichier_excel) + self.entry_fichier_excel.grid(row=1, column=1, sticky='ew') + self.button_fichier_excel = tk.Button(self.frame, text="...", command=self.command_button_fichier_excel) + self.button_fichier_excel.grid(row=1, column=2, sticky='w') # Sélection répertoire sortie self.label_dir_out = tk.Label(self.frame, text="Répertoire de sortie") - self.label_dir_out.grid(row=1, column=0, sticky='e') + self.label_dir_out.grid(row=2, column=0, sticky='e') self.value_dir_out = tk.StringVar() self.entry_dir_out = tk.Entry(self.frame, state='disabled', textvariable=self.value_dir_out) - self.entry_dir_out.grid(row=1, column=1, sticky='ew') + self.entry_dir_out.grid(row=2, column=1, sticky='ew') self.button_dir_out = tk.Button(self.frame, text="...", command=self.command_button_dir_out) - self.button_dir_out.grid(row=1, column=2, sticky='w') + self.button_dir_out.grid(row=2, column=2, sticky='w') # Sélection des unités à traiter self.label_units = tk.Label(self.frame, text="Unités à purger") - self.label_units.grid(row=2, column=0, sticky='e') + self.label_units.grid(row=3, column=0, sticky='e') self.value_units = tk.StringVar() self.entry_units = tk.Entry(self.frame, textvariable=self.value_units) - self.entry_units.grid(row=2, column=1, sticky='ew', columnspan="2") + self.entry_units.grid(row=3, column=1, sticky='ew', columnspan="2") # Bouton validation self.button_valid = tk.Button(self.frame, text="Ok", command=self.command_button_valid) - self.button_valid.grid(row=3, column=0, columnspan=3) + self.button_valid.grid(row=4, column=0, columnspan=3) # Barre de progression self.progressbar = ttk.Progressbar(self.frame, orient=tk.HORIZONTAL, mode='determinate') - self.progressbar.grid(row=4, column=0, columnspan=3, sticky='ew') + self.progressbar.grid(row=5, column=0, columnspan=3, sticky='ew') # Affichage des logs self.text_log = tk.Text(self.frame, state='disabled') - self.text_log.grid(row=0, column=3, rowspan=5, sticky='nesw') + self.text_log.grid(row=0, column=3, rowspan=6, sticky='nesw') def command_button_bdd_insee(self): self.value_bdd_insee.set(tkfiledialog.askopenfilename(title="Fichier de l'INSEE")) + def command_button_fichier_excel(self): + self.value_fichier_excel.set(tkfiledialog.askopenfilename(title="Fichier Excel")) + def command_button_dir_out(self): self.value_dir_out.set(tkfiledialog.askdirectory(title="Répertoire de sortie")) @@ -77,6 +89,11 @@ class MainApplication(tk.Frame): self.text_log.insert(tk.END, text) self.text_log.configure(state='disabled') + def clear_log(self): + self.text_log.configure(state='normal') + self.text_log.delete('1.0', tk.END) + self.text_log.configure(state='disabled') + def watch(self): if self.run: if self.pipe.poll(): @@ -84,48 +101,52 @@ class MainApplication(tk.Frame): if message.get('step', False): self.progressbar.step(message['step']) elif message.get('text', False): - print(message['text']) self.add_log(message['text']) - elif message.get('running', False): + elif 'running' in message: self.run = message['running'] elif message.get('set_max', False): self.progressbar["value"] = 0 self.progressbar['maximum'] = message['set_max'] self.parent.after(100, self.watch) else: - print("Recherche terminée") self.add_log("\nRecherche terminée\n") self.button_valid.configure(state='normal') def command_button_valid(self): self.button_valid.configure(state='disabled') + self.clear_log() self.run = True (conn1, conn2) = Pipe() self.pipe = conn1 - Worker(conn2, self.value_bdd_insee.get(), self.value_dir_out.get(), self.value_units.get().split(',')).start() + unite = self.value_units.get().split(',') + if unite == ['']: + unite = None + Worker(conn2, self.value_bdd_insee.get(), self.value_fichier_excel.get(), self.value_dir_out.get(), unite).start() self.watch() class Worker(Process): - def __init__(self, pipe, bdd_insee, dir_out, units): + def __init__(self, pipe, bdd_insee, fichier_excel, dir_out, units): Process.__init__(self) self.pipe = pipe self.bdd_insee = bdd_insee + self.fichier_excel = fichier_excel self.dir_out = dir_out self.units = units def tracker(self, step=None, text=None, set_max=None, running=None): - if step: + if step is not None: self.pipe.send({'step': step}) - elif text: + elif text is not None: self.pipe.send({'text': text}) - elif set_max: + elif set_max is not None: self.pipe.send({'set_max': set_max}) - elif running: + elif running is not None: self.pipe.send({'running': running}) def run(self): trouver_decedes(chemin_base_donnees=self.bdd_insee, + excel_path=self.fichier_excel, chemin_repertoire_sortie=self.dir_out, numeros_unites=self.units, tracker=self.tracker) diff --git a/purge-registres-deces-insee/membre_base.py b/purge-registres-deces-insee/membre_base.py index 0818009..d2e3d16 100644 --- a/purge-registres-deces-insee/membre_base.py +++ b/purge-registres-deces-insee/membre_base.py @@ -34,6 +34,9 @@ class MembreBase(ABC): nom_registres = f"{nom_registres} née {self.r_maiden_name.upper()}" return nom_registres + def get_nom_insee(self): + return f"{self.i_last_name}, {self.i_first_name}" + def set_insee(self, insee): self.i_first_name = insee.first_name self.i_last_name = insee.last_name @@ -57,7 +60,7 @@ class MembreBase(ABC): Le membre {self.get_nom_registres()} ({self.r_id}), né{feminin} le {self.r_jour:0>2}/{self.r_mois:0>2}/{self.r_annee:0>4} à {self.r_ville.upper()} semble être décédé{feminin}. -Dans le fichier de l'INSEE on peut trouver {self.i_last_name}, {self.i_first_name} +Dans le fichier de l'INSEE on peut trouver {self.get_nom_insee()} né{feminin} le {self.i_jour_naissance:0>2}/{self.i_mois_naissance:0>2}/{self.i_annee_naissance:0>4} à {self.i_ville_naissance} décédé{feminin} le {self.i_jour_deces:0>2}/{self.i_mois_deces:0>2}/{self.i_annee_deces:0>4} à {self.i_ville_deces} """ diff --git a/purge-registres-deces-insee/site_eglise.py b/purge-registres-deces-insee/site_eglise.py index 99c5f47..9a69a3c 100644 --- a/purge-registres-deces-insee/site_eglise.py +++ b/purge-registres-deces-insee/site_eglise.py @@ -45,7 +45,7 @@ class SiteEglise(MembreProvider): def complete(self): if not self.completed: member_profile = self.provider.get_member_profile(self.r_id) - self.r_maiden_name = member_profile['individual']['maidenNameGroup']['name1']['family'] + self.r_maiden_name = member_profile['individual']['maidenNameGroup']['name1']['family'].strip().split(' ')[0].upper() self.r_ville = member_profile['individual']['birthPlace'] if not self.r_ville: self.r_ville = "" diff --git a/purge-registres-deces-insee/trouver_decedes.py b/purge-registres-deces-insee/trouver_decedes.py index b474d7c..48b0dbb 100755 --- a/purge-registres-deces-insee/trouver_decedes.py +++ b/purge-registres-deces-insee/trouver_decedes.py @@ -15,6 +15,8 @@ import os from bdd_insee import BddInsee from site_eglise import SiteEglise +from excel_in import ExcelIn +from excel_out import ExcelOut def default_tracker(step=None, text=None, set_max=None, running=None): @@ -42,29 +44,35 @@ def trouver_decedes(chemin_base_donnees, numeros_unites, chemin_repertoire_sorti # Initialiser les fournisseurs de liste de membres fournisseurs_membres = list() if excel_path: - raise NotImplementedError - for unite in numeros_unites: - fournisseurs_membres.append(SiteEglise(unite, cookie_path)) + fournisseurs_membres.append(ExcelIn(excel_path)) + if numeros_unites: + for unite in numeros_unites: + fournisseurs_membres.append(SiteEglise(unite, cookie_path)) # Boucler sur la liste fournisseurs for member_provider in fournisseurs_membres: tracker(set_max=member_provider.load()) - tracker(text=member_provider.get_name()) + tracker(text=f"Recherche dans {member_provider.get_name()}\n") # Récupérer la liste des membres members = member_provider.get_member_list() - # Préparer le fichier de sortie - output_file = os.path.join(chemin_repertoire_sortie, f"liste_membres_decedes_{member_provider.get_name()}.txt") - with open(output_file, 'w') as out_file: - out_file.write("Les lieux dans le fichier de l'INSEE sont donnés en Code Officiel Géographique en vigueur au moment de la prise en compte du décès\n") - # Boucler sur la liste des membres - for member in members: - query = base_insee.find_person(member.r_first_name, member.r_last_name, member.r_maiden_name, - member.r_annee, member.r_mois, member.r_jour) - for person in query: - member.set_insee(person) - text = member.get_texte_decede() - tracker(text=text) - out_file.write(text) - tracker(step=1) + # Préparer les fichiers de sortie + output_base_name = os.path.join(chemin_repertoire_sortie, f"liste_membres_decedes_{member_provider.get_name()}") + output_txt = open(output_base_name + ".txt", 'w') + output_xls = ExcelOut(output_base_name + ".xlsx") + output_txt.write("Les lieux dans le fichier de l'INSEE sont donnés en Code Officiel Géographique en vigueur au moment de la prise en compte du décès\n") + # Boucler sur la liste des membres + for member in members: + query = base_insee.find_person(member.r_first_name, member.r_last_name, member.r_maiden_name, + member.r_annee, member.r_mois, member.r_jour) + for person in query: + member.set_insee(person) + text = member.get_texte_decede() + tracker(text=text) + output_txt.write(text) + output_xls.add_member(member) + tracker(step=1) + # Clore les fichiers de sortie + output_txt.close() + output_xls.generate_output() tracker(running=False) diff --git a/requirements.txt b/requirements.txt index b0630ba..63d8669 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,6 @@ peewee requests -browser_cookie3 \ No newline at end of file +browser_cookie3 +pandas +xlrd +numpy