Lecture et écriture des fichiers Excel + quelques bugs

- 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
This commit is contained in:
Sdj Geek 2020-07-29 09:56:37 +02:00
parent 9febc4cc55
commit 308ed11077
8 changed files with 140 additions and 42 deletions

View File

@ -26,6 +26,27 @@ except ImportError:
stdout=subprocess.PIPE, stderr=subprocess.PIPE) stdout=subprocess.PIPE, stderr=subprocess.PIPE)
print(p.communicate()) print(p.communicate())
url = "https://git.roflcopter.fr/sdjgeek/purge-registres-deces-insee/-/archive/v5.0/purge-registres-deces-insee-v5.0.zip" try:
myfile = requests.get(url) import pandas
open('purge-registres-deces-insee-v5.0.zip', 'wb').write(myfile.content) 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())

View File

@ -8,6 +8,7 @@ Classe d'accès aux données du site de l'Église
import os import os
import pandas as pd import pandas as pd
import numpy as np
from membre_base import MembreBase, MembreProvider from membre_base import MembreBase, MembreProvider
@ -25,12 +26,23 @@ class ExcelIn(MembreProvider):
def __init__(self, provider, row): def __init__(self, provider, row):
super().__init__(provider) 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 = "<VIDE>"
self.r_sexe = "F" if str(row["status"]) == "Female" else "M"
def get_name(self): def get_name(self):
return os.path.basename(self.excel_path) return os.path.basename(self.excel_path)
def load(self): 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) return len(self.dataframe)
def get_member_list(self): def get_member_list(self):

View File

@ -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)

View File

@ -38,37 +38,49 @@ class MainApplication(tk.Frame):
self.button_bdd_insee = tk.Button(self.frame, text="...", command=self.command_button_bdd_insee) 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') 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 # Sélection répertoire sortie
self.label_dir_out = tk.Label(self.frame, text="Répertoire de 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.value_dir_out = tk.StringVar()
self.entry_dir_out = tk.Entry(self.frame, state='disabled', textvariable=self.value_dir_out) 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 = 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 # Sélection des unités à traiter
self.label_units = tk.Label(self.frame, text="Unités à purger") 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.value_units = tk.StringVar()
self.entry_units = tk.Entry(self.frame, textvariable=self.value_units) 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 # Bouton validation
self.button_valid = tk.Button(self.frame, text="Ok", command=self.command_button_valid) 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 # Barre de progression
self.progressbar = ttk.Progressbar(self.frame, orient=tk.HORIZONTAL, mode='determinate') 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 # Affichage des logs
self.text_log = tk.Text(self.frame, state='disabled') 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): def command_button_bdd_insee(self):
self.value_bdd_insee.set(tkfiledialog.askopenfilename(title="Fichier de l'INSEE")) 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): def command_button_dir_out(self):
self.value_dir_out.set(tkfiledialog.askdirectory(title="Répertoire de sortie")) 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.insert(tk.END, text)
self.text_log.configure(state='disabled') 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): def watch(self):
if self.run: if self.run:
if self.pipe.poll(): if self.pipe.poll():
@ -84,48 +101,52 @@ class MainApplication(tk.Frame):
if message.get('step', False): if message.get('step', False):
self.progressbar.step(message['step']) self.progressbar.step(message['step'])
elif message.get('text', False): elif message.get('text', False):
print(message['text'])
self.add_log(message['text']) self.add_log(message['text'])
elif message.get('running', False): elif 'running' in message:
self.run = message['running'] self.run = message['running']
elif message.get('set_max', False): elif message.get('set_max', False):
self.progressbar["value"] = 0 self.progressbar["value"] = 0
self.progressbar['maximum'] = message['set_max'] self.progressbar['maximum'] = message['set_max']
self.parent.after(100, self.watch) self.parent.after(100, self.watch)
else: else:
print("Recherche terminée")
self.add_log("\nRecherche terminée\n") self.add_log("\nRecherche terminée\n")
self.button_valid.configure(state='normal') self.button_valid.configure(state='normal')
def command_button_valid(self): def command_button_valid(self):
self.button_valid.configure(state='disabled') self.button_valid.configure(state='disabled')
self.clear_log()
self.run = True self.run = True
(conn1, conn2) = Pipe() (conn1, conn2) = Pipe()
self.pipe = conn1 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() self.watch()
class Worker(Process): 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) Process.__init__(self)
self.pipe = pipe self.pipe = pipe
self.bdd_insee = bdd_insee self.bdd_insee = bdd_insee
self.fichier_excel = fichier_excel
self.dir_out = dir_out self.dir_out = dir_out
self.units = units self.units = units
def tracker(self, step=None, text=None, set_max=None, running=None): def tracker(self, step=None, text=None, set_max=None, running=None):
if step: if step is not None:
self.pipe.send({'step': step}) self.pipe.send({'step': step})
elif text: elif text is not None:
self.pipe.send({'text': text}) self.pipe.send({'text': text})
elif set_max: elif set_max is not None:
self.pipe.send({'set_max': set_max}) self.pipe.send({'set_max': set_max})
elif running: elif running is not None:
self.pipe.send({'running': running}) self.pipe.send({'running': running})
def run(self): def run(self):
trouver_decedes(chemin_base_donnees=self.bdd_insee, trouver_decedes(chemin_base_donnees=self.bdd_insee,
excel_path=self.fichier_excel,
chemin_repertoire_sortie=self.dir_out, chemin_repertoire_sortie=self.dir_out,
numeros_unites=self.units, numeros_unites=self.units,
tracker=self.tracker) tracker=self.tracker)

View File

@ -34,6 +34,9 @@ class MembreBase(ABC):
nom_registres = f"{nom_registres} née {self.r_maiden_name.upper()}" nom_registres = f"{nom_registres} née {self.r_maiden_name.upper()}"
return nom_registres return nom_registres
def get_nom_insee(self):
return f"{self.i_last_name}, {self.i_first_name}"
def set_insee(self, insee): def set_insee(self, insee):
self.i_first_name = insee.first_name self.i_first_name = insee.first_name
self.i_last_name = insee.last_name self.i_last_name = insee.last_name
@ -57,7 +60,7 @@ class MembreBase(ABC):
Le membre {self.get_nom_registres()} ({self.r_id}), Le membre {self.get_nom_registres()} ({self.r_id}),
{feminin} le {self.r_jour:0>2}/{self.r_mois:0>2}/{self.r_annee:0>4} à {self.r_ville.upper()} {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}. 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()}
{feminin} le {self.i_jour_naissance:0>2}/{self.i_mois_naissance:0>2}/{self.i_annee_naissance:0>4} à {self.i_ville_naissance} {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} 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}
""" """

View File

@ -45,7 +45,7 @@ class SiteEglise(MembreProvider):
def complete(self): def complete(self):
if not self.completed: if not self.completed:
member_profile = self.provider.get_member_profile(self.r_id) 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'] self.r_ville = member_profile['individual']['birthPlace']
if not self.r_ville: if not self.r_ville:
self.r_ville = "<VIDE>" self.r_ville = "<VIDE>"

View File

@ -15,6 +15,8 @@ import os
from bdd_insee import BddInsee from bdd_insee import BddInsee
from site_eglise import SiteEglise 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): 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 # Initialiser les fournisseurs de liste de membres
fournisseurs_membres = list() fournisseurs_membres = list()
if excel_path: if excel_path:
raise NotImplementedError fournisseurs_membres.append(ExcelIn(excel_path))
for unite in numeros_unites: if numeros_unites:
fournisseurs_membres.append(SiteEglise(unite, cookie_path)) for unite in numeros_unites:
fournisseurs_membres.append(SiteEglise(unite, cookie_path))
# Boucler sur la liste fournisseurs # Boucler sur la liste fournisseurs
for member_provider in fournisseurs_membres: for member_provider in fournisseurs_membres:
tracker(set_max=member_provider.load()) 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 # Récupérer la liste des membres
members = member_provider.get_member_list() members = member_provider.get_member_list()
# Préparer le fichier de sortie # Préparer les fichiers de sortie
output_file = os.path.join(chemin_repertoire_sortie, f"liste_membres_decedes_{member_provider.get_name()}.txt") output_base_name = os.path.join(chemin_repertoire_sortie, f"liste_membres_decedes_{member_provider.get_name()}")
with open(output_file, 'w') as out_file: output_txt = open(output_base_name + ".txt", 'w')
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") output_xls = ExcelOut(output_base_name + ".xlsx")
# Boucler sur la liste des membres 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")
for member in members: # Boucler sur la liste des membres
query = base_insee.find_person(member.r_first_name, member.r_last_name, member.r_maiden_name, for member in members:
member.r_annee, member.r_mois, member.r_jour) query = base_insee.find_person(member.r_first_name, member.r_last_name, member.r_maiden_name,
for person in query: member.r_annee, member.r_mois, member.r_jour)
member.set_insee(person) for person in query:
text = member.get_texte_decede() member.set_insee(person)
tracker(text=text) text = member.get_texte_decede()
out_file.write(text) tracker(text=text)
tracker(step=1) 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) tracker(running=False)

View File

@ -1,3 +1,6 @@
peewee peewee
requests requests
browser_cookie3 browser_cookie3
pandas
xlrd
numpy