249 lines
8.6 KiB
Python
249 lines
8.6 KiB
Python
|
|
import sys
|
|
import argparse
|
|
import logging
|
|
import docx2python
|
|
|
|
from config import Config
|
|
|
|
__LOGGER = logging.getLogger(__name__)
|
|
REPERTOIRE = "import"
|
|
|
|
parser = argparse.ArgumentParser(
|
|
description="Parse doc ressources et crée SAE",
|
|
usage='%(prog)s [options]'
|
|
)
|
|
parser.add_argument(
|
|
"DOCUMENT",
|
|
nargs="?",
|
|
default=REPERTOIRE + "/" + "ressources_v0" + ".docx"
|
|
)
|
|
parser.add_argument(
|
|
"-o",
|
|
"--outdir",
|
|
default="export",
|
|
help="repertoire resultat, defaut: export"
|
|
)
|
|
parser.add_argument(
|
|
"-r",
|
|
"--root",
|
|
default="..",
|
|
help="repertoire de base (racine) pour chercher les fichiers de données"
|
|
)
|
|
args = parser.parse_args()
|
|
Config.ROOT = args.root
|
|
|
|
__LOGGER.warning(f"{sys.argv[0]} processing {args.DOCUMENT}")
|
|
__LOGGER.warning(f"{sys.argv[0]} outputs to {args.outdir}")
|
|
|
|
# Ces imports doivent être faits après la config
|
|
from tools import *
|
|
from ressourcedocx import *
|
|
|
|
# Ouverture du document
|
|
docu = docx2python.docx2python(args.DOCUMENT)
|
|
|
|
docu = docu.body
|
|
docu[0] # Titre général
|
|
docu[1] # Tableau de synthèse des ressources
|
|
|
|
|
|
|
|
ENTETES_CHAPEAU = ["Titre", "Code", "Semestre", "Heures de formation",
|
|
"dont heures de TP",
|
|
"Heures \"projet",
|
|
"Description",
|
|
"Liste des ressources", "Type de livrable", "Mots clefs"]
|
|
ENTETES_EXEMPLES = ["Titre", "Description", "Formes", "Quelle problématique",
|
|
"Modalités"]
|
|
|
|
"""
|
|
Format du parsing issu de docx2python
|
|
[ # document
|
|
[ # table A
|
|
[ # table A row
|
|
[ # table A cell 1 <-- structure des tableaux
|
|
"""
|
|
|
|
|
|
print("*Etape 1* : Parsing")
|
|
nbre_saes = 0
|
|
last_sae = None
|
|
liste_saes = [] # la liste des saes telle qu'extraite du docx
|
|
liste_exemples = {} # la liste des exemples de chaque SAé
|
|
|
|
for i in range(1, len(docu)): # A priori un tableau
|
|
est_sae, est_exemple = False, False
|
|
try:
|
|
if "Titre de la " in docu[i][0][0][0] or "Nom de la " in docu[i][0][0][0]: # [03][00][0][0]
|
|
if "Code" in docu[i][1][0][0]:
|
|
est_sae = True
|
|
nbre_saes += 1
|
|
else: # c'est un exemple
|
|
est_exemple = True
|
|
except:
|
|
pass
|
|
|
|
if est_sae == True:
|
|
res = docu[i] # la ressource
|
|
nom_sae = caracteres_recalcitrants(res[0][1][0])
|
|
|
|
# Création de la ressource
|
|
r = SAEDocx(nom_sae, res)
|
|
liste_saes.append(r)
|
|
|
|
# Parsing des données brute de la sae
|
|
data = [None for i in range(len(ENTETES_CHAPEAU))] # les données attendues Nom, Code, ..., Mots clés
|
|
apprentissages = [None for i in range(3)] # les apprentissages des 3 compétences
|
|
coeffs = [None for i in range(3)]
|
|
|
|
non_interprete = []
|
|
for j in range(len(res)): # parcours des entêtes du tableau décrivant la ressource
|
|
ligne = res[j]
|
|
if len(ligne) == 2: # ligne de données classique champ => valeur
|
|
champ = caracteres_recalcitrants(ligne[0][0]) # le nom du champ
|
|
if champ.startswith("Nom de la"):
|
|
champ = "Titre de la" # corrige les noms/titres
|
|
i = get_indice_sans_accent_ni_espace(champ, ENTETES_CHAPEAU) # l'indice de l'entete dans ENTETES
|
|
if i != None:
|
|
data[i] = caracteres_recalcitrants("\n".join(res[j][1]))
|
|
else:
|
|
non_interprete.append((champ, ligne[1][0]))
|
|
else: # ligne de données soit chapeau (ex Compétences ciblées) soit détail par compétence
|
|
champ = ligne[0][0]
|
|
|
|
if "Apprentissage(s)" in champ: # les compétences ciblées sont déduites de la présence d'apprentissage critiques
|
|
# j+1 = les ACs par compétences
|
|
acs = res[j+2]
|
|
for k in range(len(acs)):
|
|
apprentissages[k] = caracteres_recalcitrants("\n".join(acs[k])) # fusionne les ACS (généralement sur plusieurs lignes)
|
|
elif "Compétence(s) ciblée(s)" in champ:
|
|
les_coeffs = res[j+2]
|
|
coeffs = [elmt[0] for elmt in les_coeffs]
|
|
|
|
if non_interprete: # souvent Heures de formation (incluant les TP)
|
|
|
|
__LOGGER.warning(f"Dans la saé \"{nom_sae}\", champs en trop non interprétés : " + ",".join(
|
|
[chp[0] for chp in non_interprete]))
|
|
|
|
# Analyse des champs manquants
|
|
champ_manquants = []
|
|
for (j, champ) in enumerate(ENTETES_CHAPEAU):
|
|
if not data[j]:
|
|
champ_manquants += [champ]
|
|
if champ_manquants:
|
|
__LOGGER.warning(f"Dans \"{nom_sae}\", champs manquants : " + ",".join(champ_manquants))
|
|
|
|
# Sauvegarde des champs de la ressource
|
|
info = tuple(data[1:])
|
|
r.charge_informations(*info)
|
|
r.charge_ac(apprentissages)
|
|
r.charge_coeffs(coeffs)
|
|
|
|
# nettoie le titre et le code
|
|
r.nettoie_code()
|
|
r.nettoie_titre_sae()
|
|
|
|
|
|
last_sae = r.code
|
|
liste_exemples[r.code] = []
|
|
|
|
elif est_exemple == True:
|
|
res = docu[i] # la ressource
|
|
nom_exemple = caracteres_recalcitrants(res[0][1][0])
|
|
|
|
# Création de la ressource
|
|
r = ExempleSAEDocx(nom_exemple, res, last_sae)
|
|
liste_exemples[last_sae].append(r)
|
|
|
|
# Parsing des données brute de la sae
|
|
data = [None for i in range(len(ENTETES_EXEMPLES))] # les données attendues Nom, Code, ..., Mots clés
|
|
apprentissages = [None for i in range(3)] # les apprentissages des 3 compétences
|
|
|
|
non_interprete = []
|
|
for j in range(len(res)): # parcours des entêtes du tableau décrivant la ressource
|
|
ligne = res[j]
|
|
if len(ligne) == 2: # ligne de données classique champ => valeur
|
|
champ = caracteres_recalcitrants(ligne[0][0]) # le nom du champ
|
|
i = get_indice_sans_accent_ni_espace(champ, ENTETES_EXEMPLES) # l'indice de l'entete dans ENTETES
|
|
if i != None:
|
|
data[i] = caracteres_recalcitrants("\n".join(res[j][1]))
|
|
else:
|
|
non_interprete.append((champ, ligne[1][0]))
|
|
else: # ligne de données soit chapeau (ex Compétences ciblées) soit détail par compétence
|
|
print("??? plus de 2 colonnes ?")
|
|
|
|
if non_interprete: # souvent Heures de formation (incluant les TP)
|
|
|
|
__LOGGER.warning(f"Dans l'exemple \"{nom_exemple}\", champs en trop non interprétés : " + ",".join(
|
|
[chp[0] for chp in non_interprete]))
|
|
|
|
# Analyse des champs manquants
|
|
champ_manquants = []
|
|
for (j, champ) in enumerate(ENTETES_EXEMPLES):
|
|
if not data[j]:
|
|
champ_manquants += [champ]
|
|
if champ_manquants:
|
|
__LOGGER.warning(f"Dans \"{nom_exemple}\", champs manquants : " + ",".join(champ_manquants))
|
|
|
|
# Sauvegarde des champs de la ressource
|
|
info = tuple(data[1:])
|
|
r.charge_informations(*info)
|
|
|
|
# fin du parsing
|
|
print(f"{nbre_saes} saes")
|
|
for s in liste_exemples:
|
|
print(f"{s} :" + str(len(liste_exemples[s])) + " exemples")
|
|
|
|
# ************************************************************************
|
|
print("*Etape 2* : Post-traitement")
|
|
|
|
# Post traitement des saes => gestion des heures/des acs/ + tri par semestre
|
|
print(" > SAE")
|
|
saes = {"S1" : [], "S2": []}
|
|
|
|
for s in liste_saes:
|
|
print(f"{s.nom}")
|
|
s.nettoie_champs()
|
|
|
|
# Tri dans le bon semestre
|
|
saes[s.semestre] += [s]
|
|
|
|
# Post traitement des exemples "S1" => "codesae chapeau" => "ExempleSAE"
|
|
exemples = {"S1" : {}, "S2" : {} }
|
|
print(" > Exemples")
|
|
for s in liste_exemples: # la sae
|
|
|
|
sem = get_officiel_sem_sae_by_code(s)
|
|
exemples[sem][s] = []
|
|
for e in liste_exemples[s]:
|
|
print(f"{s} : {e.nom}")
|
|
if e.nom.startswith("Caractériser un support radio"):
|
|
print("ici")
|
|
e.nettoie_champs()
|
|
|
|
# Tri dans le bon semestre
|
|
exemples[sem][s].append(e)
|
|
|
|
# Export yaml
|
|
print("*Etape 3* : Export yaml")
|
|
for sem in saes:
|
|
for s in saes[sem]:
|
|
output = s.to_yaml()
|
|
if s.code:
|
|
code_clean = s.code.replace("É", "E")
|
|
fichier = f"{args.outdir}/{code_clean}.yml"
|
|
with open(fichier, "w", encoding="utf8") as fid:
|
|
fid.write(output)
|
|
|
|
for sem in exemples:
|
|
for s in exemples[sem]:
|
|
for (i, e) in enumerate(exemples[sem][s]):
|
|
output = e.to_yaml()
|
|
code_clean = s.replace("É", "E")
|
|
fichier = f"{args.outdir}/{code_clean}_exemple{i+1}.yml"
|
|
with open(fichier, "w", encoding="utf8") as fid:
|
|
fid.write(output)
|
|
|
|
|