From 3fec540b6771f635fb756eb39ee8c960912e7294 Mon Sep 17 00:00:00 2001 From: Sdj GeeK Date: Sat, 18 Jul 2020 16:18:17 +0200 Subject: [PATCH 1/7] =?UTF-8?q?Abstraction=20de=20site=5Feglise=20pour=20d?= =?UTF-8?q?onner=20possibilit=C3=A9=20de=20recevoir=20une=20liste=20de=20m?= =?UTF-8?q?embre=20par=20un=20autre=20moyen?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- purge-registres-deces-insee/membre_base.py | 82 ++++++++++++++++++ purge-registres-deces-insee/site_eglise.py | 66 ++++++++++++-- .../trouver_decedes.py | 85 ++++++++----------- 3 files changed, 173 insertions(+), 60 deletions(-) create mode 100644 purge-registres-deces-insee/membre_base.py diff --git a/purge-registres-deces-insee/membre_base.py b/purge-registres-deces-insee/membre_base.py new file mode 100644 index 0000000..0818009 --- /dev/null +++ b/purge-registres-deces-insee/membre_base.py @@ -0,0 +1,82 @@ +from abc import ABC, abstractmethod + + +class MembreBase(ABC): + + def __init__(self, provider): + self.provider = provider + # Données issues des registres + self.r_id = None + self.r_first_name = None + self.r_last_name = None + self.r_maiden_name = None + self.r_annee = None + self.r_mois = None + self.r_jour = None + self.r_ville = None + self.r_sexe = None + + # Données issues de l'INSEE + self.i_first_name = None + self.i_last_name = None + self.i_annee_naissance = None + self.i_mois_naissance = None + self.i_jour_naissance = None + self.i_ville_naissance = None + self.i_annee_deces = None + self.i_mois_deces = None + self.i_jour_deces = None + self.i_ville_deces = None + + def get_nom_registres(self): + nom_registres = f"{self.r_last_name}, {self.r_first_name}" + if self.r_maiden_name: + nom_registres = f"{nom_registres} née {self.r_maiden_name.upper()}" + return nom_registres + + def set_insee(self, insee): + self.i_first_name = insee.first_name + self.i_last_name = insee.last_name + self.i_annee_naissance = insee.annee_naissance + self.i_mois_naissance = insee.mois_naissance + self.i_jour_naissance = insee.jour_naissance + self.i_ville_naissance = insee.code_lieu_naissance + self.i_annee_deces = insee.annee_deces + self.i_mois_deces = insee.mois_deces + self.i_jour_deces = insee.jour_deces + self.i_ville_deces = insee.code_lieu_deces + + def get_texte_decede(self): + if self.r_sexe == "F": + feminin = "e" + elif self.r_sexe == "M": + feminin = "" + else: + feminin = "(e)" + return f""" +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} +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} +""" + + +class MembreProvider(ABC): + + @abstractmethod + def load(self): + pass + + @abstractmethod + def get_name(self): + pass + + @abstractmethod + def __len__(self): + pass + + @abstractmethod + def get_member_list(self): + pass diff --git a/purge-registres-deces-insee/site_eglise.py b/purge-registres-deces-insee/site_eglise.py index 48e5731..0df1a66 100644 --- a/purge-registres-deces-insee/site_eglise.py +++ b/purge-registres-deces-insee/site_eglise.py @@ -9,29 +9,77 @@ Classe d'accès aux données du site de l'Église import requests import browser_cookie3 +from membre_base import MembreBase, MembreProvider -class SiteEglise: - def __init__(self, cookie_path=None): +class SiteEglise(MembreProvider): + + def __init__(self, unit, cookie_path=None): """ :param cookie_path: chemin vers le répertoire où inscrire les fichiers de sortie """ + self.unite = unit self.cookie_jar = browser_cookie3.firefox(cookie_file=cookie_path) + self.as_json = None - def get_member_list(self, unit_number): + def __len__(self): + return len(self.as_json) + + class Membre(MembreBase): + + def __init__(self, provider, data): + super().__init__(provider) + self.completed = False + # Données fournies + self.r_id = data['legacyCmisId'] + self.r_last_name, self.r_first_name = data['nameListPreferredLocal'].split(',') + self.r_last_name = self.r_last_name.strip().split(' ')[0] + self.r_first_name = self.r_first_name.strip().split(' ')[0] + self.r_annee, self.r_mois, self.r_jour = data['birth']['date']['date'].split('-') + self.r_sexe = data['sex'] + # Rechercher le nom de jeune fille si besoin + if data['isSpouse']: + self.complete() + + 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_ville = member_profile['individual']['birthPlace'] + if not self.r_ville: + self.r_ville = "" + self.completed = True + + def set_insee(self, insee): + self.complete() + super().set_insee(insee) + + def get_name(self): + return f"Unité_{self.unite}" + + def load(self): + r = requests.get('https://lcr.churchofjesuschrist.org/services/umlu/report/member-list', + params={'lang': "fra", 'unitNumber': self.unite}, + headers={'Accept': "application/json"}, + cookies=self.cookie_jar) + r.raise_for_status() + self.as_json = r.json() + return len(self.as_json) + + def get_member_list(self): """Recevoir la liste des membres :param unit_number: numéro de l'unité (paroisse, branche) :returns: la liste des membres sous forme d'objet JSON """ - r = requests.get('https://lcr.churchofjesuschrist.org/services/umlu/report/member-list', - params={'lang': "fra", 'unitNumber': unit_number}, - headers={'Accept': "application/json"}, - cookies=self.cookie_jar) - r.raise_for_status() - return r.json() + for member in self.as_json: + try: + yield self.Membre(self, member) + except ValueError: + print(f"Error with member [{member['nameListPreferredLocal']}, {member['birth']['date']['date']}]") + continue def get_member_profile(self, member_id): """Recevoir les informations sur un membre diff --git a/purge-registres-deces-insee/trouver_decedes.py b/purge-registres-deces-insee/trouver_decedes.py index 8b4ec39..e1fae1d 100755 --- a/purge-registres-deces-insee/trouver_decedes.py +++ b/purge-registres-deces-insee/trouver_decedes.py @@ -22,74 +22,46 @@ def default_tracker(step=None, text=None, set_max=None): print(text) -def trouver_decedes(chemin_base_donnees, numeros_unites, chemin_repertoire_sortie, cookie_path=None, tracker=None): +def trouver_decedes(chemin_base_donnees, numeros_unites, chemin_repertoire_sortie, cookie_path=None, excel_path=None, + tracker=None): """Recherche les personnes décédées dans les registres :param chemin_base_donnees: chemin vers le fichier SQLite :param numeros_unites: liste des numéros d'unités à analyser :param chemin_repertoire_sortie: chemin vers le répertoire où inscrire les fichiers de sortie :param cookie_path: chemin vers la base de donnée des cookies + :param excel_path: chemin vers le fichier Excel contenant la liste des membres à rechercher + :param tracker: Objet permettant de suivre l'avancée du traitement """ # Tracker par défaut if tracker is None: tracker = default_tracker - # Initialiser les accès aux données (INSEE et site de l'Église) + # Initialiser les accès aux données INSEE base_insee = BddInsee(chemin_base_donnees) - site_eglise = SiteEglise(cookie_path) - # Boucler sur la liste des unités + # Initialiser les fournisseurs de liste de membres + fournisseurs_membres = list() + if excel_path: + raise NotImplementedError for unite in numeros_unites: - tracker(text=f"Unité {unite}") + 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()) # Récupérer la liste des membres - members = site_eglise.get_member_list(unite) - + members = member_provider.get_member_list() # Préparer le fichier de sortie - output_file = os.path.join(chemin_repertoire_sortie, f"liste_membres_decedes_unite_{unite}.txt") + 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 - tracker(set_max=len(members)) for member in members: - # Lire les noms et date de naissance - name_registre = member['nameListPreferredLocal'] - full_birthdate = member['birth']['date']['date'] - maiden_name = None - ville_registre = None - # S'il s'agit d'une femme mariée, trouver son nom de jeune fille - if member['isSpouse']: - member_profile = site_eglise.get_member_profile(member['legacyCmisId']) - maiden_name = member_profile['individual']['maidenNameGroup']['name1']['family'] - ville_registre = member_profile['individual']['birthPlace'] - try: - last_name, first_name = name_registre.split(',') - annee_registre, mois_registre, jour_registre = full_birthdate.split('-') - except ValueError: - print(f"Error with member [{name_registre}, {full_birthdate}]") - continue - first_name = first_name.strip().split(' ')[0] - last_name = last_name.strip().split(' ')[0] - query = base_insee.find_person(first_name, last_name, maiden_name, annee_registre, mois_registre, jour_registre) - name_registre = name_registre.upper() - if maiden_name: - name_registre = f"{name_registre} née {maiden_name.upper()}" - if member['sex'] == "F": - feminin = "e" - else: - feminin = "" + 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: - if not ville_registre: - member_profile = site_eglise.get_member_profile(member['legacyCmisId']) - ville_registre = member_profile['individual']['birthPlace'] - if not ville_registre: - ville_registre = "" - text = f""" -Le membre {name_registre}, -né{feminin} le {jour_registre:0>2}/{mois_registre:0>2}/{annee_registre:0>4} à {ville_registre.upper()} -semble être décédé{feminin}. -Dans le fichier de l'INSEE on peut trouver {person.last_name}, {person.first_name} -né{feminin} le {person.jour_naissance:0>2}/{person.mois_naissance:0>2}/{person.annee_naissance:0>4} à {person.code_lieu_naissance} -décédé{feminin} le {person.jour_deces:0>2}/{person.mois_deces:0>2}/{person.annee_deces:0>4} à {person.code_lieu_deces} -""" + member.set_insee(person) + text = member.get_texte_decede() tracker(text=text) out_file.write(text) tracker(step=1) @@ -99,7 +71,18 @@ if __name__ == "__main__": parser = argparse.ArgumentParser(description='Recherche des personnes décédées dans les registres.') parser.add_argument('chemin_base_donnees', type=str, help="chemin vers la base de données") parser.add_argument('chemin_repertoire_sortie', type=str, help="chemin vers le répertoire de sortie") - parser.add_argument('numeros_unites', type=str, help="numéros des l'unités à traiter, séparés par des virgules (ex: 123,753,469)") - parser.add_argument('--cookie', '-c', type=str, help='chemin vers la base de donnée des cookies de Firefox') + parser.add_argument('--numeros_unites', '-u', type=str, help="numéros des l'unités à traiter, séparés par des virgules (ex: 123,753,469)") + parser.add_argument('--cookie', '-c', type=str, help="chemin vers la base de donnée des cookies de Firefox") + parser.add_argument('--excel', '-e', type=str, help="chemin vers le fichier Excel contenant la liste des membres à rechercher") args = parser.parse_args() - trouver_decedes(args.chemin_base_donnees, args.numeros_unites.split(','), args.chemin_repertoire_sortie, args.cookie) + + if args.numeros_unites: + numeros_unites = args.numeros_unites.split(',') + else: + numeros_unites = list() + + trouver_decedes(chemin_base_donnees=args.chemin_base_donnees, + numeros_unites=numeros_unites, + chemin_repertoire_sortie=args.chemin_repertoire_sortie, + cookie_path=args.cookie, + excel_path=args.excel) From 8856641003ede6fc1766b5a604dcda05209ac653 Mon Sep 17 00:00:00 2001 From: Sdj GeeK Date: Sat, 18 Jul 2020 16:49:02 +0200 Subject: [PATCH 2/7] =?UTF-8?q?WIP=20pr=C3=A9paration=20du=20lecteur=20de?= =?UTF-8?q?=20fichier=20excel?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- purge-registres-deces-insee/excel_in.py | 42 ++++++++++++++++++++++ purge-registres-deces-insee/site_eglise.py | 10 +++--- 2 files changed, 47 insertions(+), 5 deletions(-) create mode 100644 purge-registres-deces-insee/excel_in.py diff --git a/purge-registres-deces-insee/excel_in.py b/purge-registres-deces-insee/excel_in.py new file mode 100644 index 0000000..a5dfadf --- /dev/null +++ b/purge-registres-deces-insee/excel_in.py @@ -0,0 +1,42 @@ +""" +Copyright (c) 2020 Sdj Geek +Voir le fichier LICENSE + +Classe d'accès aux données du site de l'Église + +""" + +import os +import pandas as pd + +from membre_base import MembreBase, MembreProvider + + +class ExcelIn(MembreProvider): + + def __init__(self, excel_path): + self.excel_path = excel_path + self.dataframe = None + + def __len__(self): + return len(self.dataframe) + + class Member(MembreBase): + + def __init__(self, provider, row): + super().__init__(provider) + + def get_name(self): + return os.path.basename(self.excel_path) + + def load(self): + self.dataframe = pd.read_excel(self.excel_path) + return len(self.dataframe) + + def get_member_list(self): + for index, row in self.dataframe.iterrows(): + try: + yield self.Member(self, row) + except ValueError: + print(f"Error with member [{row}]") + continue diff --git a/purge-registres-deces-insee/site_eglise.py b/purge-registres-deces-insee/site_eglise.py index 0df1a66..99c5f47 100644 --- a/purge-registres-deces-insee/site_eglise.py +++ b/purge-registres-deces-insee/site_eglise.py @@ -14,12 +14,12 @@ from membre_base import MembreBase, MembreProvider class SiteEglise(MembreProvider): - def __init__(self, unit, cookie_path=None): + def __init__(self, unite, cookie_path=None): """ - + :param unite: numéro de l'unité (paroisse, branche) :param cookie_path: chemin vers le répertoire où inscrire les fichiers de sortie """ - self.unite = unit + self.unite = unite self.cookie_jar = browser_cookie3.firefox(cookie_file=cookie_path) self.as_json = None @@ -33,7 +33,7 @@ class SiteEglise(MembreProvider): self.completed = False # Données fournies self.r_id = data['legacyCmisId'] - self.r_last_name, self.r_first_name = data['nameListPreferredLocal'].split(',') + self.r_last_name, self.r_first_name = data['nameListPreferredLocal'].upper().split(',') self.r_last_name = self.r_last_name.strip().split(' ')[0] self.r_first_name = self.r_first_name.strip().split(' ')[0] self.r_annee, self.r_mois, self.r_jour = data['birth']['date']['date'].split('-') @@ -70,7 +70,7 @@ class SiteEglise(MembreProvider): def get_member_list(self): """Recevoir la liste des membres - :param unit_number: numéro de l'unité (paroisse, branche) + :returns: la liste des membres sous forme d'objet JSON """ From 87093bc92ce201538930405dbb6ade0a21923774 Mon Sep 17 00:00:00 2001 From: Sdj GeeK Date: Tue, 28 Jul 2020 16:50:35 +0200 Subject: [PATCH 3/7] =?UTF-8?q?Envoyer=20l'info=20que=20le=20traitement=20?= =?UTF-8?q?est=20termin=C3=A9=20=C3=A0=20l'IHM?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- purge-registres-deces-insee/trouver_decedes.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/purge-registres-deces-insee/trouver_decedes.py b/purge-registres-deces-insee/trouver_decedes.py index e1fae1d..b474d7c 100755 --- a/purge-registres-deces-insee/trouver_decedes.py +++ b/purge-registres-deces-insee/trouver_decedes.py @@ -17,7 +17,7 @@ from bdd_insee import BddInsee from site_eglise import SiteEglise -def default_tracker(step=None, text=None, set_max=None): +def default_tracker(step=None, text=None, set_max=None, running=None): if text: print(text) @@ -65,6 +65,7 @@ def trouver_decedes(chemin_base_donnees, numeros_unites, chemin_repertoire_sorti tracker(text=text) out_file.write(text) tracker(step=1) + tracker(running=False) if __name__ == "__main__": From 9febc4cc55b16f37d36833dc0d43ec86ee7a738b Mon Sep 17 00:00:00 2001 From: Sdj GeeK Date: Tue, 28 Jul 2020 16:51:42 +0200 Subject: [PATCH 4/7] =?UTF-8?q?Mettre=20la=20barre=20de=20progression=20?= =?UTF-8?q?=C3=A0=20z=C3=A9ro=20lorsqu'on=20donne=20la=20valeur=20max.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- purge-registres-deces-insee/gui_trouver_decedes.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/purge-registres-deces-insee/gui_trouver_decedes.py b/purge-registres-deces-insee/gui_trouver_decedes.py index 69c716a..5832ae6 100644 --- a/purge-registres-deces-insee/gui_trouver_decedes.py +++ b/purge-registres-deces-insee/gui_trouver_decedes.py @@ -89,6 +89,7 @@ class MainApplication(tk.Frame): elif message.get('running', False): 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: @@ -120,7 +121,7 @@ class Worker(Process): self.pipe.send({'text': text}) elif set_max: self.pipe.send({'set_max': set_max}) - elif done: + elif running: self.pipe.send({'running': running}) def run(self): From 308ed110778aeba95fd87cd89aa42023be32a373 Mon Sep 17 00:00:00 2001 From: Sdj GeeK Date: Wed, 29 Jul 2020 09:56:37 +0200 Subject: [PATCH 5/7] =?UTF-8?q?Lecture=20et=20=C3=A9criture=20des=20fichie?= =?UTF-8?q?rs=20Excel=20+=20quelques=20bugs?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Mise en place de la lecture de la liste des membres à partir d'un fichier Excel - Mise en place de l'écriture de la liste des membres décédés dans un fichier Excel - Correction du bug: le traitement ne rend pas la main à l'IHM losque terminé - Vider le texte de l'IHM lorsqu'on clique sur OK --- install.py | 27 ++++++++- purge-registres-deces-insee/excel_in.py | 14 ++++- purge-registres-deces-insee/excel_out.py | 30 ++++++++++ .../gui_trouver_decedes.py | 55 +++++++++++++------ purge-registres-deces-insee/membre_base.py | 5 +- purge-registres-deces-insee/site_eglise.py | 2 +- .../trouver_decedes.py | 44 +++++++++------ requirements.txt | 5 +- 8 files changed, 140 insertions(+), 42 deletions(-) create mode 100644 purge-registres-deces-insee/excel_out.py 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 From a26450d98de9a0f2de14ae193b8a232eba0aac33 Mon Sep 17 00:00:00 2001 From: Sdj GeeK Date: Wed, 29 Jul 2020 12:56:27 +0200 Subject: [PATCH 6/7] Tentative de creation d'un launcher pour windows --- start_windows.bat | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 start_windows.bat diff --git a/start_windows.bat b/start_windows.bat new file mode 100644 index 0000000..9e6033a --- /dev/null +++ b/start_windows.bat @@ -0,0 +1,2 @@ +python install.py +python purge-registres-deces-insee\gui_trouver_decedes.py \ No newline at end of file From e0d2949b007181d53d82a94b2fa95a8ca2d0ab52 Mon Sep 17 00:00:00 2001 From: Sdj GeeK Date: Wed, 29 Jul 2020 13:19:35 +0200 Subject: [PATCH 7/7] =?UTF-8?q?MAJ=20Changelog,=20ajout=20des=20ent=C3=AAt?= =?UTF-8?q?es?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG.md | 8 ++++++++ purge-registres-deces-insee/membre_base.py | 6 ++++++ 2 files changed, 14 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index bc6effc..bbe52e5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Changelog +### [v6.0] 2020-07-29 +- Lecture de la liste des membres à partir d'un fichier Excel +- Écriture de la liste des membres décédés dans un fichier Excel +- Vider le texte de l'IHM lorsqu'on clique sur OK +- Fichier BAT pour installer et lancer l'IHM sous Windows +- BUG: le traitement rend la main à l'IHM losque terminé +- BUG: la barre de progression est remise à zero entre chaque traitement + ### [v5.0] 2020-07-17 - Mise en place d'une interface graphique - Ajout d'un fichier install.py diff --git a/purge-registres-deces-insee/membre_base.py b/purge-registres-deces-insee/membre_base.py index d2e3d16..14e179e 100644 --- a/purge-registres-deces-insee/membre_base.py +++ b/purge-registres-deces-insee/membre_base.py @@ -1,3 +1,9 @@ +""" +Copyright (c) 2020 Sdj Geek +Voir le fichier LICENSE + +""" + from abc import ABC, abstractmethod