2021-03-29 13:50:16 +02:00
|
|
|
import re
|
2021-03-30 07:59:21 +02:00
|
|
|
from officiel import *
|
2021-03-30 07:56:41 +02:00
|
|
|
from modeles import *
|
2021-04-02 14:59:08 +02:00
|
|
|
from officiel import supprime_accent_espace, get_code_from_nom_using_dict
|
2021-03-30 11:00:23 +02:00
|
|
|
import ruamel.yaml
|
|
|
|
from ruamel.yaml.scalarstring import FoldedScalarString as folded
|
2021-03-29 13:50:16 +02:00
|
|
|
|
2021-04-02 15:24:56 +02:00
|
|
|
|
2021-03-29 11:20:05 +02:00
|
|
|
__LOGGER = logging.getLogger(__name__)
|
|
|
|
|
2021-04-04 09:34:03 +02:00
|
|
|
class Docx():
|
|
|
|
"""Classe de base pour les ressources/saé/exemples du docx"""
|
2021-04-04 11:15:59 +02:00
|
|
|
__LOGGER = logging.getLogger(__name__)
|
|
|
|
|
2021-04-02 14:59:08 +02:00
|
|
|
def __init__(self, nom, brut):
|
2021-03-29 11:20:05 +02:00
|
|
|
self.nom = nom
|
2021-04-12 11:32:09 +02:00
|
|
|
self.code = None # chargé ultérieurement
|
2021-04-04 11:15:59 +02:00
|
|
|
self.brut = brut # les données brutes de la ressource/saé
|
|
|
|
self.semestre = None # le semestre de la ressource/saé (chargé ultérieurement)
|
|
|
|
self.apprentissages = None # les acs (chargés ultérieurement)
|
|
|
|
self.mots = None # les mots-clés chargés ultérieurement
|
2021-04-07 11:51:19 +02:00
|
|
|
self.coeffs = None # chargés ultérieurement
|
2021-04-04 09:34:03 +02:00
|
|
|
|
|
|
|
def charge_ac(self, apprentissages):
|
|
|
|
self.apprentissages = apprentissages
|
|
|
|
|
2021-04-07 11:51:19 +02:00
|
|
|
def charge_coeffs(self, coeffs):
|
|
|
|
self.coeffs = coeffs
|
|
|
|
|
2021-04-04 09:34:03 +02:00
|
|
|
def __str__(self):
|
|
|
|
print(self.nom + " " + self.code)
|
|
|
|
|
2021-04-04 11:15:59 +02:00
|
|
|
def nettoie_semestre(self):
|
|
|
|
"""Pour une ressource, ou une SAE, nettoie le champ semestre"""
|
|
|
|
if self.semestre:
|
|
|
|
if "1" in self.semestre:
|
|
|
|
self.semestre = "S1"
|
|
|
|
elif "2" in self.semestre:
|
|
|
|
self.semestre = "S2"
|
|
|
|
else:
|
|
|
|
Docx.__LOGGER.warning(f"nettoie_semestre : dans \"{self.nom}, PAS de semestre => rattaché au S2")
|
|
|
|
self.semestre = "S2"
|
|
|
|
else:
|
|
|
|
Docx.__LOGGER.warning(f"nettoie_semestre : dans \"{self.nom}, PAS de semestre => rattaché au S2")
|
|
|
|
self.semestre = "S2"
|
|
|
|
|
|
|
|
def nettoie_acs(self):
|
|
|
|
"""Nettoie les acs d'une ressource ou d'une saé,
|
|
|
|
en les remplaçant par leur code pour les 3 compétences"""
|
|
|
|
|
|
|
|
if len(self.apprentissages) != 3:
|
|
|
|
Docx.__LOGGER.warning(f"nettoie_acs : Problème dans le nombre de compétences de {self.nom}")
|
|
|
|
|
|
|
|
dico = {}
|
|
|
|
for comp in range(3):
|
|
|
|
donnees = self.apprentissages[comp] # chaine de caractères listant les ACS
|
|
|
|
|
|
|
|
acs_avec_code = devine_acs_by_code(donnees) # récupère les codes des acs
|
|
|
|
acs_avec_code = [ac.replace(" ", "") for ac in acs_avec_code] # supprime les espaces inutiles
|
|
|
|
|
|
|
|
acs_avec_nom = devine_code_by_nom_from_dict(donnees, DATA_ACS) # récupère les codes en utilisant les noms
|
|
|
|
acs_avec_nom = [ac.replace(" ", "") for ac in acs_avec_nom] # supprime les espaces inutiles
|
|
|
|
|
|
|
|
if acs_avec_code and set(acs_avec_nom).intersection(set(acs_avec_code)) != set(acs_avec_nom):
|
|
|
|
Docx.__LOGGER.warning(f"Dans {self.nom}, revoir les ACS : {acs_avec_code} vs {acs_avec_nom}")
|
|
|
|
|
|
|
|
acs_finaux = sorted(list(set(acs_avec_code + acs_avec_nom)))
|
2021-04-07 11:51:19 +02:00
|
|
|
if acs_finaux:
|
|
|
|
dico["RT" + str(comp + 1)] = acs_finaux
|
2021-04-04 11:15:59 +02:00
|
|
|
|
|
|
|
self.apprentissages = dico # Mise à jour du champ
|
|
|
|
|
|
|
|
def nettoie_mots_cles(self):
|
|
|
|
mots = self.mots # .encode('utf8', 'ignore').decode('utf8')
|
|
|
|
mots = mots.replace(".", "").replace(";", ",")
|
|
|
|
liste_mots = mots.split(",")
|
2021-04-09 08:13:12 +02:00
|
|
|
liste_mots = [l.strip() for l in liste_mots if l.strip()] # supprime les espaces inutiles et les lignes vides
|
2021-04-04 11:15:59 +02:00
|
|
|
mots = ", ".join(liste_mots)
|
|
|
|
self.mots = mots
|
|
|
|
|
|
|
|
def nettoie_titre(self, data_titres):
|
|
|
|
"""Nettoie le titre d'une ressource ou d'une SAE en utilisant les titres officiels
|
|
|
|
fournis dans le yaml (via le dictionnaire DATA_RESSOURCES)"""
|
|
|
|
|
|
|
|
def devine_nom(champ):
|
|
|
|
champ_purge = supprime_accent_espace(champ)
|
|
|
|
for sem in data_titres:
|
|
|
|
for code in data_titres[sem]:
|
|
|
|
nom_purge = supprime_accent_espace(data_titres[sem][code])
|
|
|
|
if champ_purge.startswith(nom_purge):
|
|
|
|
return data_titres[sem][code] # le bon nom
|
|
|
|
|
|
|
|
old = self.nom
|
|
|
|
titre = devine_nom(self.nom)
|
|
|
|
if titre and titre != old:
|
2021-04-05 12:05:04 +02:00
|
|
|
Docx.__LOGGER.warning(f"nettoie_titre : {old} => titre deviné \"{titre}\"")
|
2021-04-04 11:15:59 +02:00
|
|
|
self.nom = titre
|
|
|
|
|
2021-04-07 11:51:19 +02:00
|
|
|
def nettoie_coeffs(self):
|
|
|
|
coeffs_finaux = {}
|
|
|
|
for (comp, chaine) in enumerate(self.coeffs):
|
|
|
|
if "coef" in chaine: # s'il y a un coeff
|
|
|
|
champ = chaine.split(" ")
|
|
|
|
coeff = eval(champ[1])
|
|
|
|
coeffs_finaux["RT" + str(comp + 1)] = coeff
|
|
|
|
elif "X" in chaine:
|
|
|
|
coeff = 0
|
|
|
|
coeffs_finaux["RT" + str(comp + 1)] = coeff
|
|
|
|
self.coeffs = coeffs_finaux
|
|
|
|
|
2021-04-04 09:34:03 +02:00
|
|
|
def dico_to_yaml(self, dico):
|
|
|
|
output = ruamel.yaml.dump(dico, Dumper=ruamel.yaml.RoundTripDumper,
|
|
|
|
allow_unicode=True, width=100)
|
|
|
|
# Purge les lignes vides en trop
|
|
|
|
lignes = output.split("\n")
|
|
|
|
lignes_finales = []
|
|
|
|
for (i, ligne) in enumerate(lignes):
|
|
|
|
if ligne.rstrip() == "":
|
2021-04-04 11:15:59 +02:00
|
|
|
if i != len(lignes)-1 and lignes[i+1].rstrip() != "":
|
2021-04-04 09:34:03 +02:00
|
|
|
lignes_finales.append(ligne) # ajoute la ligne si la suivante n'est pas vide
|
|
|
|
else:
|
|
|
|
lignes_finales.append(ligne)
|
|
|
|
output = "\n".join(lignes_finales)
|
2021-04-04 22:09:01 +02:00
|
|
|
|
|
|
|
# Ajoute les espaces manquants dans les listes markdown
|
|
|
|
# écrite sur plusieurs lignes
|
2021-04-04 09:34:03 +02:00
|
|
|
lignes = output.split("\n") # pour vérif
|
2021-04-04 22:09:01 +02:00
|
|
|
lignes_finales = []
|
|
|
|
avec_marqueur = False
|
|
|
|
last_marqueur = 0
|
|
|
|
for (i, ligne) in enumerate(lignes):
|
|
|
|
ligne = ligne.replace("\t", " "*2)
|
|
|
|
if " *" in ligne and avec_marqueur == False:
|
|
|
|
avec_marqueur = True
|
|
|
|
last_marqueur = " *"
|
|
|
|
elif " *" in ligne and avec_marqueur == False:
|
|
|
|
avec_marqueur = True
|
|
|
|
last_marqueur = " *"
|
|
|
|
else: # pas de marqueur
|
|
|
|
if ligne.strip() == "" or ligne[0] != " ":
|
|
|
|
avec_marqueur = False # fin du marqueur
|
|
|
|
elif ligne.strip() != "" and avec_marqueur == True:
|
|
|
|
if last_marqueur == " *":
|
|
|
|
ligne = " "*4 + ligne.lstrip()
|
|
|
|
else:
|
|
|
|
ligne = " "*6 + ligne.lstrip()
|
|
|
|
lignes_finales.append(ligne)
|
|
|
|
|
|
|
|
output = "\n".join(lignes_finales)
|
|
|
|
|
2021-04-11 18:32:13 +02:00
|
|
|
# Remplace http(s) URLs pour markdown
|
2021-04-12 16:24:09 +02:00
|
|
|
if "11" in self.code:
|
|
|
|
print("ici")
|
2021-04-11 18:32:13 +02:00
|
|
|
output = re.sub( r"(http(s)?://[\w\d:#@%/;~_?\+-=\\\.&]*)", r"[\1](\1)", output )
|
|
|
|
# Remplace les guillemets
|
|
|
|
# ne traite pas tous les cas, mais arrange la majorité
|
|
|
|
output = re.sub( r"\"(.*?)\"", r"«\1»", output, flags=re.DOTALL)
|
|
|
|
# On utilise les guillements français (ajout automatique des bons espaces)
|
|
|
|
output = output.replace("«", r"\og ").replace("»", r"\fg{}")
|
|
|
|
|
2021-04-04 09:34:03 +02:00
|
|
|
return output
|
|
|
|
|
|
|
|
class RessourceDocx(Docx):
|
|
|
|
"""Classe modélisant les ressources, lorsqu'elles sont extraites du docx"""
|
2021-04-04 11:15:59 +02:00
|
|
|
__LOGGER = logging.getLogger(__name__)
|
2021-03-29 11:20:05 +02:00
|
|
|
|
|
|
|
def charge_informations(self, code, semestre, heures_encadrees, tp, sae, prerequis, description, mots):
|
|
|
|
self.code = code
|
|
|
|
self.semestre = semestre # <--
|
|
|
|
self.heures_encadrees = heures_encadrees
|
|
|
|
self.tp = tp
|
|
|
|
self.sae = sae
|
|
|
|
self.prerequis = prerequis
|
|
|
|
self.description = description
|
2021-03-30 07:56:41 +02:00
|
|
|
self.contexte = None
|
|
|
|
self.contenu = None
|
2021-03-29 11:20:05 +02:00
|
|
|
self.mots = mots
|
|
|
|
|
2021-04-04 11:15:59 +02:00
|
|
|
|
2021-04-04 11:58:44 +02:00
|
|
|
def nettoie_titre_ressource(self):
|
2021-04-04 11:15:59 +02:00
|
|
|
"""Nettoie le titre d'une ressource ou d'une SAE en utilisant les titres officiels
|
|
|
|
fournis dans le yaml (via le dictionnaire DATA_RESSOURCES)"""
|
2021-04-05 12:05:04 +02:00
|
|
|
old = self.nom
|
2021-04-04 11:15:59 +02:00
|
|
|
self.nettoie_titre(DATA_RESSOURCES)
|
2021-04-05 12:05:04 +02:00
|
|
|
titre2 = get_officiel_ressource_name_by_code(self.code)
|
|
|
|
if titre2 != self.nom:
|
|
|
|
self.nom = titre2
|
|
|
|
RessourceDocx.__LOGGER.warning(f"nettoie_titre : {old} => titre d'après PN \"{titre2}\"")
|
2021-04-04 11:15:59 +02:00
|
|
|
|
|
|
|
def nettoie_code(self):
|
|
|
|
"""Recherche le code de la forme RXXX"""
|
|
|
|
if self.code:
|
|
|
|
codes = devine_ressources_by_code(self.code)
|
|
|
|
|
|
|
|
if len(codes) == 1:
|
|
|
|
self.code = codes[0]
|
|
|
|
else:
|
|
|
|
code_devine = get_code_from_nom_using_dict(self.nom, DATA_RESSOURCES)
|
|
|
|
if code_devine:
|
|
|
|
RessourceDocx.__LOGGER.warning(f"nettoie_code : \"{self.nom}\" => code {code_devine}")
|
|
|
|
self.code = code_devine
|
|
|
|
else:
|
|
|
|
self.code = None
|
|
|
|
|
|
|
|
if not self.code:
|
|
|
|
RessourceDocx.__LOGGER.warning(f"nettoie_code : \"{self.nom}\" => code manquant")
|
|
|
|
|
|
|
|
def nettoie_prerequis(self):
|
|
|
|
"""Nettoie les prérequis"""
|
2021-04-12 11:32:09 +02:00
|
|
|
if not self.prerequis or AUCUN_PREREQUIS.lower() in self.prerequis.lower():
|
|
|
|
self.prerequis = AUCUN_PREREQUIS
|
|
|
|
else:
|
|
|
|
ressources = nettoie_liste_ressources(self.prerequis)
|
|
|
|
if ressources:
|
|
|
|
self.prerequis = ressources
|
2021-04-04 11:15:59 +02:00
|
|
|
|
|
|
|
def nettoie_sae(self):
|
|
|
|
"""Nettoie le champ SAe d'une ressource en détectant les codes"""
|
|
|
|
SAE_avec_code = devine_sae_by_code(self.sae)
|
|
|
|
liste = [l.rstrip() for l in SAE_avec_code]
|
|
|
|
self.sae = liste
|
|
|
|
if not self.sae:
|
|
|
|
RessourceDocx.__LOGGER.warning(f"nettoie_sae: dans {self.nom} pas de SAE (:")
|
|
|
|
|
|
|
|
def nettoie_heures(self):
|
|
|
|
"""Nettoie le champ (horaire) (de la forme 46h ou 33...) pour en extraire la valeur numérique :
|
|
|
|
le champ peut contenir 2 volumes (heures formation puis heures tp), auquel cas les 2 valeurs sont renvoyées
|
|
|
|
dans un tuple"""
|
2021-04-12 11:32:09 +02:00
|
|
|
volumes = None
|
2021-04-04 11:15:59 +02:00
|
|
|
if self.heures_encadrees: # si les heures encadrées sont renseignées
|
|
|
|
volumes = nettoie_champ_heure(self.heures_encadrees)
|
|
|
|
if self.tp:
|
|
|
|
self.tp = nettoie_champ_heure(self.tp)
|
|
|
|
|
|
|
|
if isinstance(volumes, int):
|
|
|
|
self.heures_encadrees = volumes
|
|
|
|
elif isinstance(volumes, tuple):
|
|
|
|
self.heures_encadrees = volumes[0]
|
|
|
|
if not self.tp:
|
|
|
|
self.tp = volumes[1]
|
|
|
|
elif self.tp != volumes[1]:
|
|
|
|
RessourceDocx.__LOGGER.warning(r"nettoie_heure: ans {self.nom}, pb dans les heures tp/td")
|
|
|
|
else:
|
|
|
|
self.heures_encadrees = None
|
|
|
|
|
|
|
|
def split_description(self):
|
|
|
|
"""Découpe le champ description en un contexte+un contenu ; si pas possible """
|
2021-04-12 08:29:19 +02:00
|
|
|
if self.code == "R110":
|
|
|
|
print("ici")
|
2021-04-04 11:15:59 +02:00
|
|
|
champs = self.description.split("\n")
|
|
|
|
champs = [c for c in champs if c] # supprime les lignes vides
|
|
|
|
|
|
|
|
indicea = 0 # la ligne mentionnant le contexte
|
|
|
|
if True in [ligne.startswith("Contexte et ") for ligne in champs]: # la ligne commençant par Contenus
|
|
|
|
indicea = [ligne.startswith("Contexte et ") for ligne in champs].index(True)
|
|
|
|
|
|
|
|
indicec = 0
|
|
|
|
contexte = []
|
2021-04-12 11:32:09 +02:00
|
|
|
marqueur = False
|
|
|
|
identifiants = ["Contenus", "Objectifs visés"] # Identifiant marquant la ligne des contenus
|
|
|
|
for id in identifiants:
|
|
|
|
presence = [ligne.startswith(id) for ligne in champs]
|
|
|
|
if True in presence and not marqueur: # la ligne commençant par l'identifiant
|
|
|
|
indicec = presence.index(True)
|
|
|
|
marqueur = True
|
2021-04-04 11:15:59 +02:00
|
|
|
if True in [ligne.startswith("Contexte et ") for ligne in champs]:
|
|
|
|
contexte = champs[indicea + 1:indicec]
|
|
|
|
else:
|
|
|
|
contexte = champs[:indicec]
|
|
|
|
# suppression des lignes vides
|
|
|
|
contexte = "\n".join(remove_ligne_vide(contexte))
|
|
|
|
# suppression des liens
|
2021-04-12 16:24:09 +02:00
|
|
|
|
2021-04-04 11:15:59 +02:00
|
|
|
contexte = remove_link(contexte)
|
|
|
|
if not contexte:
|
|
|
|
contexte = "Aucun"
|
|
|
|
contenu = "\n".join(champs[indicec + 1:])
|
|
|
|
|
|
|
|
# sauvegarde des champs
|
|
|
|
self.contexte = contexte
|
|
|
|
self.contenu = contenu
|
|
|
|
|
|
|
|
def nettoie_contenu(self):
|
|
|
|
"""Partant du contenu détaillé d'une ressource, la transforme
|
|
|
|
en markdown en générant les listes à puces"""
|
|
|
|
contenu = self.contenu.replace(" / ", "/")
|
|
|
|
self.contenu = convert_to_markdown(contenu)
|
|
|
|
|
2021-04-12 11:32:09 +02:00
|
|
|
def nettoie_contexte(self):
|
|
|
|
"""Partant du contexte détaillé d'une ressource, la transforme
|
|
|
|
en markdown en générant les listes à puces"""
|
|
|
|
contexte = self.contexte.replace(" / ", "/")
|
|
|
|
self.contexte = convert_to_markdown(contexte)
|
|
|
|
|
2021-04-05 12:05:04 +02:00
|
|
|
def nettoie_champ(self):
|
|
|
|
"""Lance le nettoyage des champs"""
|
|
|
|
self.nettoie_code()
|
|
|
|
self.nettoie_titre_ressource()
|
|
|
|
self.nettoie_heures()
|
|
|
|
|
|
|
|
self.nettoie_semestre()
|
|
|
|
self.nettoie_acs()
|
|
|
|
self.nettoie_sae()
|
|
|
|
self.nettoie_prerequis()
|
|
|
|
self.nettoie_mots_cles()
|
2021-04-07 11:51:19 +02:00
|
|
|
self.nettoie_coeffs()
|
2021-04-05 12:05:04 +02:00
|
|
|
|
|
|
|
# Remet en forme le descriptif
|
|
|
|
self.split_description()
|
2021-04-12 11:32:09 +02:00
|
|
|
self.nettoie_contexte()
|
2021-04-05 12:05:04 +02:00
|
|
|
self.nettoie_contenu()
|
2021-04-11 18:32:13 +02:00
|
|
|
print(f"{self.code} {self.semestre}")
|
2021-04-04 11:15:59 +02:00
|
|
|
|
2021-03-30 09:22:21 +02:00
|
|
|
def to_yaml(self):
|
2021-04-02 15:31:15 +02:00
|
|
|
"""Exporte la ressource en yaml"""
|
2021-03-30 09:22:21 +02:00
|
|
|
dico = {"nom": self.nom,
|
|
|
|
"code": self.code,
|
2021-04-02 15:31:15 +02:00
|
|
|
"semestre" : int(self.semestre[1]),
|
|
|
|
"heures_formation": self.heures_encadrees if self.heures_encadrees else "???",
|
|
|
|
"heures_tp": self.tp if self.tp else "???",
|
2021-04-07 11:51:19 +02:00
|
|
|
"coeffs": self.coeffs,
|
2021-03-30 09:22:21 +02:00
|
|
|
"acs": self.apprentissages,
|
2021-03-30 12:34:59 +02:00
|
|
|
"sae": self.sae,
|
2021-03-30 09:22:21 +02:00
|
|
|
"prerequis": self.prerequis,
|
2021-04-02 15:24:56 +02:00
|
|
|
"contexte": folded(self.contexte),
|
|
|
|
"contenu": folded(self.contenu),
|
|
|
|
"motscles": self.mots if self.mots else ""
|
2021-03-30 09:22:21 +02:00
|
|
|
}
|
2021-04-04 09:34:03 +02:00
|
|
|
return self.dico_to_yaml(dico)
|
2021-03-30 09:22:21 +02:00
|
|
|
|
2021-04-02 14:59:08 +02:00
|
|
|
def nettoie_champ_heure(champ):
|
|
|
|
try: # champ contenant uniquement un nbre d'heure
|
|
|
|
volumes = int(champ)
|
|
|
|
return volumes
|
|
|
|
except:
|
|
|
|
volumes = re.findall("(\d{2}\D|\d{1}\D)", champ)
|
|
|
|
if len(volumes) == 1:
|
|
|
|
return int(volumes[0][:-1])
|
|
|
|
elif len(volumes) == 2:
|
|
|
|
volumes = sorted(volumes, reverse=True)
|
|
|
|
return (int(volumes[0][:-1]), int(volumes[1][:-1]))
|
|
|
|
|
2021-03-29 16:22:51 +02:00
|
|
|
|
2021-04-04 11:15:59 +02:00
|
|
|
def nettoie_liste_ressources(contenu):
|
|
|
|
"""Nettoie un contenu contenant une liste ressources, en extrayant les codes ressources
|
|
|
|
et en les fournissant les codes extraits dans une liste
|
|
|
|
"""
|
|
|
|
R_avec_code = devine_ressources_by_code(contenu)
|
|
|
|
R_avec_nom = devine_code_by_nom_from_dict(contenu, DATA_RESSOURCES)
|
|
|
|
liste = R_avec_code + R_avec_nom
|
2021-04-05 12:05:04 +02:00
|
|
|
liste = [l.strip().replace(",", "").replace(".", "") for l in liste] # supprime les espaces et les ponctuations restantes
|
2021-04-04 11:15:59 +02:00
|
|
|
return sorted(list(set(liste)))
|
2021-03-29 16:22:51 +02:00
|
|
|
|
|
|
|
|
2021-03-29 17:25:16 +02:00
|
|
|
def devine_acs_by_code(champ):
|
|
|
|
"""Recherche les codes ressources de la forme ACXXX ou AC0XXX dans champ ;
|
|
|
|
ramène les codes AC0XXX à 3 chiffres.
|
|
|
|
"""
|
|
|
|
codes3 = re.findall(r"(AC[0-9][0-9][0-9]\D)", champ) # de code à 3 chiffres
|
|
|
|
codes4 = re.findall(r"(AC0[0-9][0-9][0-9])", champ)
|
2021-03-29 16:22:51 +02:00
|
|
|
|
2021-04-02 09:09:41 +02:00
|
|
|
codes3 = [c.rstrip() for c in codes3]
|
|
|
|
codes4 = [c.rstrip() for c in codes4]
|
|
|
|
codes4 += [ "AC0" + c[-3:] for c in codes3] # ajoute les 0 manquants des acs (codage AC0111)
|
2021-04-05 12:05:04 +02:00
|
|
|
codes4 = [c.strip() for c in codes4]
|
2021-03-30 19:35:52 +02:00
|
|
|
return sorted(list(set(codes4)))
|
2021-03-29 17:25:16 +02:00
|
|
|
|
2021-04-04 11:15:59 +02:00
|
|
|
|
2021-03-30 07:56:41 +02:00
|
|
|
def devine_ressources_by_code(champ):
|
|
|
|
"""Recherche les codes ressources de la forme RXXX dans champ ;
|
|
|
|
"""
|
2021-04-05 12:05:04 +02:00
|
|
|
codes1 = re.findall(r"(R\d{3})", champ) # de code à 3 chiffres
|
|
|
|
codes2 = re.findall(r"(R\d{3}\D)", champ)
|
2021-04-07 11:51:19 +02:00
|
|
|
codes = codes1 + [c.strip() for c in codes2 if "|" not in c]
|
2021-03-30 07:56:41 +02:00
|
|
|
return sorted(list(set(codes)))
|
|
|
|
|
|
|
|
def devine_ressources_by_nom(donnees):
|
|
|
|
"""Partant d'une chaine de caractères, détermine les ressources
|
|
|
|
présentes dans la donnée, en utilisant les infos officielles de
|
|
|
|
ressources.yml"""
|
|
|
|
donnees_purge = supprime_accent_espace(donnees)
|
|
|
|
codes = []
|
|
|
|
for sem in DATA_RESSOURCES:
|
|
|
|
for code in DATA_RESSOURCES[sem]:
|
|
|
|
nom_purge = supprime_accent_espace(DATA_RESSOURCES[sem][code])
|
|
|
|
if nom_purge in donnees_purge:
|
|
|
|
codes += [code]
|
|
|
|
return sorted(list(set(codes)))
|
|
|
|
|
2021-03-30 12:34:59 +02:00
|
|
|
def devine_sae_by_code(donnees):
|
|
|
|
"""Partant d'une chaine de caractères, détermine les codes des SAE"""
|
2021-04-04 11:15:59 +02:00
|
|
|
codes = re.findall(r"(SAE\d\d)", donnees)
|
|
|
|
codes += re.findall(r"(SAÉ\d\d)", donnees)# de code à 3 chiffres
|
2021-03-30 12:34:59 +02:00
|
|
|
for (i, code) in enumerate(codes):
|
|
|
|
codes[i] = codes[i].replace("E", "É")
|
|
|
|
return sorted(list(set(codes)))
|
|
|
|
|
2021-03-30 16:55:47 +02:00
|
|
|
def remove_link(contenu):
|
|
|
|
liens = re.findall("(<a\s.*\">)", contenu)
|
|
|
|
for m in liens:
|
|
|
|
contenu = contenu.replace(m, "")
|
|
|
|
contenu = contenu.replace("</a>", "")
|
|
|
|
return contenu
|
|
|
|
|
2021-03-30 11:00:23 +02:00
|
|
|
def remove_ligne_vide(contenus):
|
|
|
|
"""Supprime les lignes vides"""
|
2021-04-02 10:46:42 +02:00
|
|
|
if isinstance(contenus, list):
|
|
|
|
return [c for c in contenus if c.rstrip()]
|
|
|
|
else: # contenu = chaine
|
2021-04-07 11:51:19 +02:00
|
|
|
if get_marqueurs(contenus):
|
|
|
|
temp = contenus.split("\n")
|
|
|
|
temp = [t for t in temp if t.replace("\t", "").rstrip()]
|
|
|
|
return "\n".join(temp)
|
|
|
|
else: # pas de marqueur => respect des paragraphes
|
|
|
|
contenus = contenus.replace("\n\n", "\\\\\n")
|
|
|
|
temp = contenus.split("\n")
|
|
|
|
temp = [t for t in temp if t.replace("\t", "").rstrip()]
|
|
|
|
return "\n".join(temp)
|
2021-03-30 11:00:23 +02:00
|
|
|
|
|
|
|
def get_marqueur_numerique(contenu):
|
|
|
|
"""Revoie la liste des marqueurs numériques"""
|
2021-04-02 09:09:41 +02:00
|
|
|
m = re.findall(r"(\d/|\d\s/)", contenu)
|
2021-04-07 11:51:19 +02:00
|
|
|
#m += re.findall(r"(\d\s\)|\d\))", contenu) # les marqueurs de la forme 1)
|
|
|
|
m += re.findall(r"(\d\s\))", contenu)
|
2021-04-05 12:05:04 +02:00
|
|
|
m += re.findall(r"(--)\s", contenu)
|
|
|
|
m += re.findall(r"(--)\t", contenu)
|
2021-03-30 11:00:23 +02:00
|
|
|
return m
|
|
|
|
|
2021-04-02 15:38:53 +02:00
|
|
|
def get_marqueurs(contenu):
|
|
|
|
"""Renvoie la liste des marqueurs (à 1 caractère) partant d'un contenu - splitable en plusieurs lignes
|
|
|
|
(éventuellement vide)"""
|
|
|
|
contenus = [ligne.rstrip() for ligne in contenu.split("\n")] # les contenus
|
|
|
|
|
2021-03-30 07:56:41 +02:00
|
|
|
marqueurs = []
|
|
|
|
for ligne in contenus:
|
2021-04-02 15:24:56 +02:00
|
|
|
m = re.search(r"(\t)*", ligne) # y a-t-il des tabulations ?
|
2021-03-30 07:56:41 +02:00
|
|
|
if m.group() != "":
|
|
|
|
ajout = m.group()
|
|
|
|
else:
|
|
|
|
ajout = ""
|
2021-04-02 15:38:53 +02:00
|
|
|
ligne = ligne.replace("\t","").rstrip() # supprime les tabulations pour rapatrier le marqueur en début de ligne
|
2021-04-02 15:24:56 +02:00
|
|
|
if ligne: # si la ligne n'est pas vide, cherche le marqueur en début de ligne (si 1 caractère)
|
|
|
|
if ligne[0] not in string.ascii_letters and ligne[0] != "É" and ligne[0] != "/":
|
|
|
|
marqueurs += [ajout + ligne[0]] # tous les symboles
|
2021-03-30 07:56:41 +02:00
|
|
|
|
2021-03-30 11:00:23 +02:00
|
|
|
marqueurs_finaux = [] # tri les marqueurs en supprimant les doublons et en gardant un ordre (pour détecter les sous listes)
|
2021-03-30 07:56:41 +02:00
|
|
|
for m in marqueurs:
|
2021-03-30 11:00:23 +02:00
|
|
|
if m not in marqueurs_finaux:
|
2021-03-30 07:56:41 +02:00
|
|
|
marqueurs_finaux.append(m)
|
2021-03-30 11:00:23 +02:00
|
|
|
return marqueurs_finaux
|
|
|
|
|
2021-04-02 15:38:53 +02:00
|
|
|
def get_marqueur_from_liste(ligne, marqueurs):
|
2021-03-30 19:35:52 +02:00
|
|
|
"""Renvoie le marqueur qui marque le début d'une ligne parmi une liste de marqueurs recherchés"""
|
|
|
|
for m in marqueurs:
|
|
|
|
if ligne.startswith(m):
|
|
|
|
return m
|
|
|
|
|
2021-03-30 11:09:43 +02:00
|
|
|
|
2021-04-02 15:24:56 +02:00
|
|
|
def remplace_marqueur_numerique_with_caracteres(contenu):
|
|
|
|
"""Remplace les marqueurs numériques par des marqueurs > lorsque présents dans un contenu"""
|
2021-03-30 11:00:23 +02:00
|
|
|
marqueurs_numeriques = get_marqueur_numerique(contenu)
|
|
|
|
for m in marqueurs_numeriques: # remplace les marqueurs numériques
|
|
|
|
contenu = contenu.replace(m, ">")
|
2021-04-02 15:24:56 +02:00
|
|
|
return contenu
|
|
|
|
|
2021-04-02 15:38:53 +02:00
|
|
|
def convert_to_markdown(contenu):
|
|
|
|
"""Convertit un contenu avec des marqueurs en markdown"""
|
2021-04-04 11:15:59 +02:00
|
|
|
contenu = remove_link(contenu) # supprime les liens
|
|
|
|
|
2021-04-02 15:24:56 +02:00
|
|
|
contenu = remplace_marqueur_numerique_with_caracteres(contenu)
|
2021-04-02 15:38:53 +02:00
|
|
|
marqueurs_finaux = get_marqueurs(contenu)
|
|
|
|
lignes = contenu.split("\n")
|
|
|
|
contenus_fin = lignes[:] # copie des ligne
|
|
|
|
for (i, ligne) in enumerate(lignes):
|
|
|
|
m = get_marqueur_from_liste(ligne, marqueurs_finaux) # identifie la présence d'un marqueur dans la ligne
|
2021-03-30 11:09:43 +02:00
|
|
|
if m:
|
|
|
|
pos = marqueurs_finaux.index(m)
|
2021-04-05 12:05:04 +02:00
|
|
|
ligne = "\t" * (pos) + "* " + ligne.replace(m, "").replace("\t", "").rstrip()
|
|
|
|
# corrige les espaces après les marqueurs
|
|
|
|
champ = re.findall(r"(\*\s+)\w", ligne)
|
|
|
|
for c in champ:
|
|
|
|
ligne = ligne.replace(c, "* ")
|
|
|
|
contenus_fin[i] = ligne
|
2021-04-03 09:53:25 +02:00
|
|
|
|
2021-04-02 09:09:41 +02:00
|
|
|
contenu = "\n\n".join(contenus_fin)
|
2021-04-04 22:09:01 +02:00
|
|
|
|
2021-04-02 15:38:53 +02:00
|
|
|
return contenu
|
2021-03-30 07:56:41 +02:00
|
|
|
|
2021-03-30 11:00:23 +02:00
|
|
|
|
2021-04-04 11:15:59 +02:00
|
|
|
class SAEDocx(Docx):
|
|
|
|
"""Classe modélisant un chapeau de SAé relu dans les docx"""
|
|
|
|
__LOGGER = logging.getLogger(__name__)
|
2021-04-02 14:59:08 +02:00
|
|
|
|
|
|
|
def charge_informations(self, code, semestre, heures_encadrees, tp, projet, description, ressources, livrables, mots):
|
|
|
|
self.code = code
|
|
|
|
self.semestre = semestre # <--
|
|
|
|
self.heures_encadrees = heures_encadrees
|
|
|
|
self.tp = tp
|
|
|
|
self.projet = projet
|
|
|
|
self.description = description
|
|
|
|
self.ressources = ressources
|
|
|
|
self.livrables = livrables
|
|
|
|
self.mots = mots
|
|
|
|
|
2021-04-04 11:15:59 +02:00
|
|
|
def nettoie_titre_sae(self):
|
|
|
|
"""Nettoie le titre d'une SAE en utilisant les titres officiels
|
|
|
|
fournis dans le yaml (via le dictionnaire DATA_RESSOURCES)"""
|
2021-04-05 12:05:04 +02:00
|
|
|
old = self.nom
|
2021-04-04 11:15:59 +02:00
|
|
|
self.nettoie_titre(DATA_SAES)
|
2021-04-05 12:05:04 +02:00
|
|
|
titre2 = get_officiel_sae_name_by_code(self.code)
|
|
|
|
if titre2 != self.nom:
|
|
|
|
self.nom = titre2
|
|
|
|
SAEDocx.__LOGGER.warning(f"nettoie_titre : {old} => titre d'après PN \"{titre2}\"")
|
2021-04-04 11:15:59 +02:00
|
|
|
|
|
|
|
def nettoie_code(self):
|
|
|
|
"""Recherche les codes de la forme SAE|éXX """
|
|
|
|
if self.code:
|
|
|
|
codes = devine_sae_by_code(self.code)
|
|
|
|
if len(codes) == 1:
|
|
|
|
self.code = codes[0]
|
|
|
|
else:
|
|
|
|
code_devine = get_code_from_nom_using_dict(self.nom, DATA_SAES)
|
|
|
|
if code_devine:
|
|
|
|
SAEDocx.__LOGGER.warning(f"nettoie_code : \"{self.nom}\" => code {code_devine}")
|
|
|
|
self.code = code_devine
|
|
|
|
else:
|
|
|
|
self.code = None
|
|
|
|
if not self.code:
|
|
|
|
SAEDocx.__LOGGER.warning(f"nettoie_code : \"{self.nom}\" => code manquant")
|
|
|
|
|
|
|
|
def nettoie_heures_sae(self):
|
|
|
|
"""Nettoie les champs (horaires) des saes"""
|
|
|
|
if self.heures_encadrees: # si les heures encadrées sont renseignées
|
|
|
|
self.heures_encadrees = nettoie_champ_heure(self.heures_encadrees)
|
|
|
|
else:
|
|
|
|
SAEDocx.__LOGGER.warning(f"nettoie_heures_sae: dans {self.nom}, manque les heures de formation")
|
|
|
|
self.heures_encadrees = "???"
|
|
|
|
if self.tp:
|
|
|
|
self.tp = nettoie_champ_heure(self.tp)
|
|
|
|
else:
|
|
|
|
SAEDocx.__LOGGER.warning(f"nettoie_heures_sae: dans {self.nom}, manque les heures de tp")
|
|
|
|
self.tp = "???"
|
|
|
|
|
|
|
|
if self.projet:
|
|
|
|
self.projet = nettoie_champ_heure(self.projet)
|
|
|
|
else:
|
|
|
|
SAEDocx.__LOGGER.warning(f"nettoie_heures_sae: dans {self.nom}, manque les heures de projet")
|
|
|
|
self.projet = "???"
|
|
|
|
|
|
|
|
try:
|
|
|
|
if self.heures_encadrees < self.tp:
|
|
|
|
SAEDocx.__LOGGER.warning(f"nettoie_heures_sae: dans {self.nom}, pb dans les heures formations/tp")
|
|
|
|
except:
|
|
|
|
pass
|
|
|
|
|
|
|
|
def nettoie_livrables_sae(self):
|
|
|
|
"""Partant du contenu détaillé d'une ressource, la transforme
|
|
|
|
en markdown en générant les listes à puces"""
|
|
|
|
self.livrables = convert_to_markdown(self.livrables)
|
|
|
|
|
|
|
|
def nettoie_ressources(self):
|
|
|
|
"""Nettoie le champ ressource d'une sae en détectant les codes"""
|
|
|
|
self.ressources = nettoie_liste_ressources(self.ressources)
|
|
|
|
if not self.ressources:
|
|
|
|
SAEDocx.__LOGGER.warning(f"nettoie_ressources: dans {self.nom} pas de ressources (:")
|
|
|
|
|
|
|
|
def nettoie_description(self):
|
|
|
|
"""Nettoie le champ description"""
|
2021-04-07 11:51:19 +02:00
|
|
|
if self.description:
|
|
|
|
self.description = convert_to_markdown(self.description)
|
|
|
|
else:
|
|
|
|
self.description = ""
|
2021-04-03 09:53:25 +02:00
|
|
|
|
2021-04-07 11:51:19 +02:00
|
|
|
def nettoie_champs(self):
|
|
|
|
"""Lance le nettoyage de tous les champs de la saé"""
|
|
|
|
self.nettoie_heures_sae()
|
|
|
|
self.nettoie_semestre()
|
|
|
|
self.nettoie_acs()
|
|
|
|
self.nettoie_ressources()
|
|
|
|
self.nettoie_description()
|
|
|
|
self.nettoie_livrables_sae()
|
|
|
|
self.nettoie_mots_cles()
|
|
|
|
self.nettoie_coeffs()
|
2021-04-02 14:59:08 +02:00
|
|
|
|
2021-04-02 16:08:14 +02:00
|
|
|
def to_yaml(self):
|
2021-04-07 11:51:19 +02:00
|
|
|
"""Exporte la saé en yaml"""
|
2021-04-02 16:08:14 +02:00
|
|
|
dico = {"titre": self.nom,
|
|
|
|
"code": self.code,
|
|
|
|
"semestre": int(self.semestre[1]),
|
|
|
|
"heures_encadrees": self.heures_encadrees if self.heures_encadrees else "???",
|
|
|
|
"tp": self.tp if self.tp else "???",
|
|
|
|
"projet": self.projet if self.projet else "???",
|
|
|
|
"description": folded(self.description),
|
2021-04-07 11:51:19 +02:00
|
|
|
"coeffs": self.coeffs,
|
2021-04-02 16:08:14 +02:00
|
|
|
"acs": self.apprentissages,
|
|
|
|
"ressources": self.ressources,
|
|
|
|
"livrables": folded(self.livrables),
|
|
|
|
"motscles": self.mots if self.mots else ""
|
|
|
|
}
|
2021-04-04 11:15:59 +02:00
|
|
|
return self.dico_to_yaml(dico)
|
2021-04-02 16:08:14 +02:00
|
|
|
|
|
|
|
|
2021-04-04 11:15:59 +02:00
|
|
|
class ExempleSAEDocx(Docx):
|
|
|
|
"""Classe modélisant les exemples de SAE tel que relu dans les Docx"""
|
2021-04-02 14:59:08 +02:00
|
|
|
|
2021-04-03 09:53:25 +02:00
|
|
|
def __init__(self, nom, brut, code):
|
2021-04-04 11:15:59 +02:00
|
|
|
self.nom = nom.rstrip()
|
2021-04-02 14:59:08 +02:00
|
|
|
self.brut = brut # les données brutes de la ressource
|
2021-04-03 09:53:25 +02:00
|
|
|
self.code = code # code de la SAE à laquelle l'exemple est raccroché
|
|
|
|
# Ajoute le semestre de la SAE
|
|
|
|
self.semestre = int(get_officiel_sem_sae_by_code(code)[1])
|
2021-04-02 14:59:08 +02:00
|
|
|
|
|
|
|
def charge_informations(self, description, formes, problematique, modalite):
|
|
|
|
self.description = description
|
|
|
|
self.formes = formes # <--
|
|
|
|
self.problematique = problematique
|
|
|
|
self.modalite = modalite
|
|
|
|
|
2021-04-04 11:15:59 +02:00
|
|
|
def nettoie_description(self):
|
|
|
|
"""Nettoie la description d'un exemple de SAE"""
|
|
|
|
self.description = convert_to_markdown(self.description)
|
|
|
|
|
|
|
|
def nettoie_problematique(self):
|
|
|
|
"""Nettoie la description d'un exemple de SAE"""
|
|
|
|
if self.problematique:
|
|
|
|
self.problematique = convert_to_markdown(self.problematique)
|
|
|
|
else:
|
|
|
|
self.problematique = ""
|
|
|
|
|
|
|
|
def nettoie_modalite(self):
|
|
|
|
"""Nettoie les modalités (d'évaluation) d'un exemple de SAE"""
|
2021-04-12 16:24:09 +02:00
|
|
|
if "12" in self.code:
|
|
|
|
print("ici")
|
|
|
|
|
2021-04-04 11:15:59 +02:00
|
|
|
if self.modalite:
|
|
|
|
self.modalite = convert_to_markdown(self.modalite)
|
|
|
|
else:
|
2021-04-12 16:24:09 +02:00
|
|
|
self.modalite = ""
|
2021-04-04 11:15:59 +02:00
|
|
|
|
2021-04-05 12:05:04 +02:00
|
|
|
def nettoie_formes(self):
|
|
|
|
"""Nettoie les modalités (d'évaluation) d'un exemple de SAE"""
|
|
|
|
if self.formes:
|
|
|
|
self.formes = convert_to_markdown(self.formes)
|
|
|
|
else:
|
|
|
|
self.formes = ""
|
|
|
|
|
|
|
|
|
2021-04-04 11:15:59 +02:00
|
|
|
def nettoie_champs(self):
|
|
|
|
"""Déclenche le nettoyage des champs de l'exemple"""
|
2021-04-05 12:05:04 +02:00
|
|
|
self.nom = self.nom.strip()
|
2021-04-04 11:15:59 +02:00
|
|
|
self.nettoie_modalite()
|
|
|
|
self.nettoie_description()
|
2021-04-04 11:58:44 +02:00
|
|
|
self.nettoie_problematique()
|
2021-04-05 12:05:04 +02:00
|
|
|
self.nettoie_formes()
|
2021-04-04 11:15:59 +02:00
|
|
|
|
2021-04-03 09:53:25 +02:00
|
|
|
def to_yaml(self):
|
|
|
|
"""Exporte la ressource en yaml"""
|
|
|
|
dico = {"titre": self.nom,
|
|
|
|
"code": self.code,
|
|
|
|
"semestre": self.semestre,
|
|
|
|
"description": folded(self.description),
|
2021-04-05 12:05:04 +02:00
|
|
|
"formes": folded(self.formes),
|
2021-04-03 14:55:05 +02:00
|
|
|
"problematique": folded(self.problematique) if self.problematique !="" else "",
|
2021-04-03 09:53:25 +02:00
|
|
|
"modalite": folded(self.modalite),
|
|
|
|
}
|
2021-04-04 11:15:59 +02:00
|
|
|
return self.dico_to_yaml(dico)
|
2021-04-02 14:59:08 +02:00
|
|
|
|
2021-03-29 17:25:16 +02:00
|
|
|
if __name__=="__main__":
|
|
|
|
# Eléments de test
|
|
|
|
for sem in DATA_RESSOURCES:
|
|
|
|
for code in DATA_RESSOURCES[sem]:
|
|
|
|
nom_data = supprime_accent_espace(DATA_RESSOURCES[sem][code])
|
|
|
|
print(nom_data)
|