forked from viennet/Referentiels
197 lines
7.1 KiB
Python
197 lines
7.1 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 yaml",
|
|
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
|
|
import tools
|
|
from tools import get_indice, get_indice_sans_accent_ni_espace
|
|
from ressource import get_matrices_ac_ressource
|
|
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
|
|
nbre_ressources = 0
|
|
|
|
|
|
ENTETES = ["Nom", "Code", "Semestre", "Heures de formation", "dont heures de TP",
|
|
"SAÉ", "Prérequis", "Descriptif", "Mots"]
|
|
|
|
"""
|
|
Format du parsing issu de docx2python
|
|
[ # document
|
|
[ # table A
|
|
[ # table A row
|
|
[ # table A cell 1 <-- structure des tableaux
|
|
"""
|
|
|
|
liste_ressources = [] # la liste des ressources telle qu'extrait du docx
|
|
print("*Etape 1* : Parsing")
|
|
|
|
for i in range(2, len(docu)): # A priori un tableau
|
|
est_ressource = False
|
|
try:
|
|
if "Nom de la ressource" in docu[i][0][0][0]: # [03][00][0][0]
|
|
est_ressource = True
|
|
nbre_ressources += 1
|
|
except:
|
|
pass
|
|
|
|
if est_ressource == True:
|
|
res = docu[i] # la ressource
|
|
nom_ressource = tools.caracteres_recalcitrants(res[0][1][0])
|
|
|
|
# Création de la ressource
|
|
r = RessourceDocx(nom_ressource, res)
|
|
liste_ressources.append(r)
|
|
|
|
# if len(res) != 15:
|
|
# __LOGGER.warning(f"Champs en trop ou manquants dans \"{nom_ressource}\"")
|
|
# Parsing des données brute de la ressource
|
|
data = [None for i in range(len(ENTETES))] # 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 = ligne[0][0] # le nom du champ
|
|
i = get_indice_sans_accent_ni_espace(champ, ENTETES) # l'indice de l'entete dans ENTETES
|
|
if i != None:
|
|
data[i] = tools.caracteres_recalcitrants("\n".join(res[j][1]))
|
|
if champ == "Prérequis" and not data[i]:
|
|
data[i] = "aucun"
|
|
print(f"Dans {nom_ressource}, complète les prérequis à \"aucun\"")
|
|
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 "Apprentissages" 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] = tools.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)
|
|
|
|
try:
|
|
indice_champ = [chp[0] for chp in non_interprete].index("Heures de formation (incluant les TP)")
|
|
except:
|
|
indice_champ = -1
|
|
if indice_champ >= 0: # si le champ "Heures de formation (incluant les TP)" est trouvé
|
|
# tente de réinjecter les heures dans Heures encadrées si elles n'on pas déjà été renseignées
|
|
indice_heure = get_indice("formation encadrée", ENTETES)
|
|
if not data[indice_heure]:
|
|
print(f"Dans \"{nom_ressource}\", réinjection de \"Heures de formation (incluant les TP)\" dans \"formation encadrée\"")
|
|
data[indice_heure] = champ[1]
|
|
non_interprete = non_interprete[:indice_champ] + non_interprete[indice_champ+1:] # supprime le champ
|
|
|
|
if non_interprete:
|
|
__LOGGER.warning(f"Dans \"{nom_ressource}\", 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):
|
|
if not data[j]:
|
|
champ_manquants += [champ]
|
|
if champ_manquants:
|
|
__LOGGER.warning(f"Dans \"{nom_ressource}\", 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)
|
|
|
|
# fin du parsing
|
|
print(f"{nbre_ressources} ressources")
|
|
|
|
# ************************************************************************
|
|
|
|
# Post traitement des ressources => gestion des heures/des acs/ + tri par semestre
|
|
ressources = {"S1" : [], "S2": []}
|
|
|
|
for (i, r) in enumerate(liste_ressources):
|
|
if r.nom.startswith("Projet "):
|
|
print("ici")
|
|
r.nettoie_champ()
|
|
|
|
# Remet en forme les mots-clés
|
|
# Tri dans le bon semestre
|
|
ressources[r.semestre] += [r]
|
|
|
|
# complète les codes d'après les numéros
|
|
for sem in ressources:
|
|
for (i, r) in enumerate(ressources[sem]):
|
|
if not r.code:
|
|
if i == 0:
|
|
r.code = "R" + sem[1] + "01"
|
|
elif ressources[sem][i-1].code:
|
|
r.code = "R" + sem[1] + "{:02d}".format(int(ressources[sem][i-1].code[-2:])+1)
|
|
|
|
# ************************************************************************
|
|
# Affichages divers
|
|
# Le tableau des heures ressources
|
|
for sem in ressources: # parcours des semestres
|
|
# print(f"Semestre {sem}")
|
|
chaine = affiche_bilan_heures(ressources, sem)
|
|
|
|
|
|
# Matrice ACS/ressources
|
|
matrices = {}
|
|
les_codes_acs = [code for comp in DATA_ACS for code in DATA_ACS[comp]]
|
|
nbre_acs = len(les_codes_acs)
|
|
|
|
# Export yaml
|
|
WITH_EXPORT = True
|
|
for sem in ressources:
|
|
for r in ressources[sem]:
|
|
output = r.to_yaml()
|
|
if WITH_EXPORT and r.code:
|
|
fichier = f"{args.outdir}/{r.code}.yml"
|
|
__LOGGER.warning(f"writing '{fichier}")
|
|
with open(fichier, "w", encoding="utf8") as fid:
|
|
fid.write(output)
|
|
|