débute le traitement des saé

This commit is contained in:
Cléo Baras 2021-04-02 14:59:08 +02:00
parent 2bb604b77a
commit bb4bd79b6d
8 changed files with 301 additions and 191 deletions

View File

@ -63,7 +63,9 @@ Aucun
% {\bfseries Ancrage et contexte professionnel :} \\ % {\bfseries Ancrage et contexte professionnel :} \\
\csname ressourceancrage\CODE\endcsname \\ \csname ressourceancrage\CODE\endcsname \\
{\bfseries Contenus :} \\ {\bfseries Contenus :} \\
%{\setlength{\extrarowheight}{1pt}
\csname ressourcecontenudetaille\CODE\endcsname \csname ressourcecontenudetaille\CODE\endcsname
%}
\end{tabular} \end{tabular}
} }

View File

@ -3,6 +3,9 @@ import docx2python
from ressourcedocx import * from ressourcedocx import *
import logging import logging
from tools import get_indice, get_indice_sans_accent_ni_espace
__LOGGER = logging.getLogger(__name__) __LOGGER = logging.getLogger(__name__)
REPERTOIRE = "import" REPERTOIRE = "import"
@ -19,22 +22,6 @@ nbre_ressources = 0
ENTETES = ["Nom", "Code", "Semestre", "Heures de formation", "dont heures de TP", ENTETES = ["Nom", "Code", "Semestre", "Heures de formation", "dont heures de TP",
"SAÉ", "Prérequis", "Descriptif", "Mots"] "SAÉ", "Prérequis", "Descriptif", "Mots"]
def get_indice(champ):
"""Récupère l'indice d'une entête"""
for (i, entete) in enumerate(ENTETES):
if entete in champ:
return i
return None
def get_indice_sans_accent_ni_espace(champ):
"""Récupère l'indice d'une entête en se débarrassant des majuscules/caractères spéciaux/espace"""
champ_purge = supprime_accent_espace(champ)
for (i, entete) in enumerate(ENTETES):
entete_purge = supprime_accent_espace(entete)
if entete_purge in champ_purge:
return i
return None
""" """
Format du parsing issu de docx2python Format du parsing issu de docx2python
@ -75,7 +62,7 @@ for i in range(2, len(docu)): # A priori un tableau
ligne = res[j] ligne = res[j]
if len(ligne) == 2: # ligne de données classique champ => valeur if len(ligne) == 2: # ligne de données classique champ => valeur
champ = ligne[0][0] # le nom du champ champ = ligne[0][0] # le nom du champ
i = get_indice_sans_accent_ni_espace(champ) # l'indice de l'entete dans ENTETES i = get_indice_sans_accent_ni_espace(champ, ENTETES) # l'indice de l'entete dans ENTETES
if i != None: if i != None:
data[i] = "\n".join(res[j][1]) data[i] = "\n".join(res[j][1])
if champ == "Prérequis" and not data[i]: if champ == "Prérequis" and not data[i]:
@ -99,7 +86,7 @@ for i in range(2, len(docu)): # A priori un tableau
indice_champ = -1 indice_champ = -1
if indice_champ >= 0: # si le champ "Heures de formation (incluant les TP)" est trouvé 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 # 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") indice_heure = get_indice("formation encadrée", ENTETES)
if not data[indice_heure]: if not data[indice_heure]:
print(f"Dans \"{nom_ressource}\", réinjection de \"Heures de formation (incluant les TP)\" dans \"formation encadrée\"") print(f"Dans \"{nom_ressource}\", réinjection de \"Heures de formation (incluant les TP)\" dans \"formation encadrée\"")
data[indice_heure] = champ[1] data[indice_heure] = champ[1]
@ -131,8 +118,8 @@ ressources = {"S1" : [], "S2": []}
for r in liste_ressources: for r in liste_ressources:
nettoie_titre(r) nettoie_titre(r)
nettoie_heure(r) nettoie_heure_ressource(r)
nettoie_code(r) nettoie_code(r, type="ressource")
nettoie_semestre(r) nettoie_semestre(r)
nettoie_acs(r) nettoie_acs(r)
nettoie_sae(r) nettoie_sae(r)

View File

@ -1,12 +1,13 @@
import docx2python import docx2python
from ressource import * from ressourcedocx import *
from tools import *
import logging import logging
__LOGGER = logging.getLogger(__name__) __LOGGER = logging.getLogger(__name__)
REPERTOIRE = "import" REPERTOIRE = "import"
DOCUMENT = "000 compilation-saes 2021-03-29T11_10_11.377Z" DOCUMENT = "sae_v0"
# Ouverture du document # Ouverture du document
docu = docx2python.docx2python(REPERTOIRE + "/" + DOCUMENT + ".docx") docu = docx2python.docx2python(REPERTOIRE + "/" + DOCUMENT + ".docx")
@ -14,29 +15,16 @@ docu = docx2python.docx2python(REPERTOIRE + "/" + DOCUMENT + ".docx")
docu = docu.body docu = docu.body
docu[0] # Titre général docu[0] # Titre général
docu[1] # Tableau de synthèse des ressources docu[1] # Tableau de synthèse des ressources
nbre_ressources = 0
ENTETES_CHAPEAU = ["Titre", "Code", "Semestre", "Heures de formation", "dont heures de TP", "Heures \"projet",
"Description des objectifs", ENTETES_CHAPEAU = ["Titre", "Code", "Semestre", "Heures de formation",
"dont heures de TP",
"Heures \"projet",
"Description",
"Liste des ressources", "Type de livrable", "Mots clefs"] "Liste des ressources", "Type de livrable", "Mots clefs"]
ENTETES_EXEMPLES = ["Titre", "Compétence", "Description des objectifs", "Types"] ENTETES_EXEMPLES = ["Titre", "Description", "Formes", "Quelle problématique",
def get_indice(champ): "Modalités"]
"""Récupère l'indice d'une entête"""
for (i, entete) in enumerate(ENTETES):
if entete in champ:
return i
return None
def get_indice_sans_accent_ni_espace(champ):
"""Récupère l'indice d'une entête en se débarrassant des majuscules/caractères spéciaux/espace"""
champ_purge = supprime_accent_espace(champ)
for (i, entete) in enumerate(ENTETES):
entete_purge = supprime_accent_espace(entete)
if entete_purge in champ_purge:
return i
return None
""" """
Format du parsing issu de docx2python Format du parsing issu de docx2python
@ -46,30 +34,35 @@ Format du parsing issu de docx2python
[ # table A cell 1 <-- structure des tableaux [ # 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 print("*Etape 1* : Parsing")
est_ressource = False 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: try:
if "Nom de la ressource" in docu[i][0][0][0]: # [03][00][0][0] if "Titre de la " in docu[i][0][0][0] or "Nom de la " in docu[i][0][0][0]: # [03][00][0][0]
est_ressource = True if "Code" in docu[i][1][0][0]:
nbre_ressources += 1 est_sae = True
nbre_saes += 1
else: # c'est un exemple
est_exemple = True
except: except:
pass pass
if est_ressource == True: if est_sae == True:
res = docu[i] # la ressource res = docu[i] # la ressource
nom_ressource = res[0][1][0] nom_sae = res[0][1][0]
# Création de la ressource # Création de la ressource
r = RessourceDocx(nom_ressource, res) r = SAEDocx(nom_sae, res)
liste_ressources.append(r) liste_saes.append(r)
# if len(res) != 15: # Parsing des données brute de la sae
# __LOGGER.warning(f"Champs en trop ou manquants dans \"{nom_ressource}\"") data = [None for i in range(len(ENTETES_CHAPEAU))] # les données attendues Nom, Code, ..., Mots clés
# 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 apprentissages = [None for i in range(3)] # les apprentissages des 3 compétences
non_interprete = [] non_interprete = []
@ -77,17 +70,17 @@ for i in range(2, len(docu)): # A priori un tableau
ligne = res[j] ligne = res[j]
if len(ligne) == 2: # ligne de données classique champ => valeur if len(ligne) == 2: # ligne de données classique champ => valeur
champ = ligne[0][0] # le nom du champ champ = ligne[0][0] # le nom du champ
i = get_indice_sans_accent_ni_espace(champ) # l'indice de l'entete dans ENTETES 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: if i != None:
data[i] = "\n".join(res[j][1]) data[i] = "\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: else:
non_interprete.append((champ, ligne[1][0])) 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 else: # ligne de données soit chapeau (ex Compétences ciblées) soit détail par compétence
champ = ligne[0][0] champ = ligne[0][0]
if "Apprentissages" in champ: # les compétences ciblées sont déduites de la présence d'apprentissage critiques
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 # j+1 = les ACs par compétences
acs = res[j+2] acs = res[j+2]
for k in range(len(acs)): for k in range(len(acs)):
@ -95,105 +88,132 @@ for i in range(2, len(docu)): # A priori un tableau
if non_interprete: # souvent Heures de formation (incluant les TP) if non_interprete: # souvent Heures de formation (incluant les TP)
try: __LOGGER.warning(f"Dans la saé \"{nom_sae}\", champs en trop non interprétés : " + ",".join(
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")
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])) [chp[0] for chp in non_interprete]))
# Analyse des champs manquants # Analyse des champs manquants
champ_manquants = [] champ_manquants = []
for (j, champ) in enumerate(ENTETES): for (j, champ) in enumerate(ENTETES_CHAPEAU):
if not data[j]: if not data[j]:
champ_manquants += [champ] champ_manquants += [champ]
if champ_manquants: if champ_manquants:
__LOGGER.warning(f"Dans \"{nom_ressource}\", champs manquants : " + ",".join(champ_manquants)) __LOGGER.warning(f"Dans \"{nom_sae}\", champs manquants : " + ",".join(champ_manquants))
# Sauvegarde des champs de la ressource # Sauvegarde des champs de la ressource
info = tuple(data[1:]) info = tuple(data[1:])
r.charge_informations(*info) r.charge_informations(*info)
r.charge_ac(apprentissages) r.charge_ac(apprentissages)
# nettoie le titre et le code
nettoie_titre(r)
nettoie_code(r, type="sae")
last_sae = r.code
liste_exemples[r.code] = []
elif est_exemple == True:
res = docu[i] # la ressource
nom_exemple = res[0][1][0]
# Création de la ressource
r = ExempleSAEDocx(nom_exemple, res)
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 = 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] = "\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 # fin du parsing
print(f"{nbre_ressources} ressources") print(f"{nbre_saes} saes")
for s in liste_exemples:
print(f"{s} :" + str(len(liste_exemples[s])) + " exemples")
# ************************************************************************ # ************************************************************************
# Post traitement des ressources => gestion des heures/des acs/ + tri par semestre # Post traitement des saes => gestion des heures/des acs/ + tri par semestre
ressources = {"S1" : [], "S2": []} saes = {"S1" : [], "S2": []}
for r in liste_ressources:
# Nettoie titre
nettoie_titre(r)
# Nettoie le champ heures_encadrees
nettoie_heure(r)
# Nettoie les codes
nettoie_code(r)
# Nettoie les semestres
nettoie_semestre(r)
# Remet en forme les ACs
nettoie_acs(r)
# Remet en forme les saé
nettoie_sae(r)
# Remet en forme les pré-requis
nettoie_prerequis(r)
# Remet en forme le descriptif
split_description(r)
nettoie_contenus(r)
# 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)
for sem in ressources:
# print("Matrice du semestre " + sem)
(matrices[sem], chaine) = get_matrices_ac_ressource(ressources, sem)
# 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 = "export/{}.yml".format(r.code)
with open(fichier, "w", encoding="utf8") as fid:
fid.write(output)
for s in liste_saes:
nettoie_heure_sae(s)
nettoie_semestre(s)
nettoie_acs(s)
nettoie_ressources(s)
print("ici")
#
# # Remet en forme les pré-requis
# nettoie_prerequis(r)
#
# # Remet en forme le descriptif
# split_description(r)
# nettoie_contenus(r)
#
# # 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)
#
# for sem in ressources:
# # print("Matrice du semestre " + sem)
# (matrices[sem], chaine) = get_matrices_ac_ressource(ressources, sem)
#
# # 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 = "export/{}.yml".format(r.code)
# with open(fichier, "w", encoding="utf8") as fid:
# fid.write(output)
#

View File

@ -93,28 +93,28 @@ def affiche_bilan_heures(ressources, sem):
chaine += trait + "\n" chaine += trait + "\n"
return chaine return chaine
def get_officiel_name_by_code_using_dict(code, dico):
"""Extrait un nom à partir d'un code (pour les RESSOURCES ou les SAES)"""
for sem in dico:
for rcode in dico[sem]:
if rcode==code:
return dico[sem][code]
def get_officiel_ressource_name_by_code(code): def get_officiel_ressource_name_by_code(code):
"""Pour un code valide, fournit le nom officiel de la ressource (sans connaissance du semestre)""" """Pour un code valide, fournit le nom officiel de la ressource (sans connaissance du semestre)"""
for sem in DATA_RESSOURCES: return get_officiel_name_by_code_using_dict(code, DATA_RESSOURCES)
for rcode in DATA_RESSOURCES[sem]:
if rcode==code:
return DATA_RESSOURCES[sem][code]
def get_officiel_sae_name_by_code(code): def get_officiel_sae_name_by_code(code):
"""Pour un code valide, fournit le nom officiel de la sae (sans connaissance du semestre)""" """Pour un code valide, fournit le nom officiel de la sae (sans connaissance du semestre)"""
for sem in DATA_SAES: return get_officiel_name_by_code_using_dict(code, DATA_SAES)
for rcode in DATA_SAES[sem]:
if rcode==code:
return DATA_SAES[sem][code]
def get_code_from_nom(ressource): def get_code_from_nom_using_dict(ressource, dico):
"""Récupère le code d'une ressource d'après son nom en utilisant les noms officiels """Récupère le code d'une ressource d'après son nom en utilisant les noms officiels
des ressources du yaml""" des ressources du yaml si dico == DATA_RESSOURCES ; sinon fait de même avec les SAE"""
nom = supprime_accent_espace(ressource.nom) nom = supprime_accent_espace(ressource.nom)
for sem in DATA_RESSOURCES: for sem in dico:
for code in DATA_RESSOURCES[sem]: for code in dico[sem]:
nom_data = supprime_accent_espace(DATA_RESSOURCES[sem][code]) nom_data = supprime_accent_espace(dico[sem][code])
if nom.startswith(nom_data): if nom.startswith(nom_data):
return code return code

View File

@ -9,7 +9,7 @@ S1:
R108: "Bases des systèmes d'exploitation" R108: "Bases des systèmes d'exploitation"
R109: "Introduction aux technologies Web" R109: "Introduction aux technologies Web"
R110: "Anglais de communication et initiation au vocabulaire technique" R110: "Anglais de communication et initiation au vocabulaire technique"
R111: "Expression-Culture-Communication Professionnelles (ECC1)" R111: "Expression-Culture-Communication Professionnelles 1"
R112: "PPP: Connaître son champ d'activité" R112: "PPP: Connaître son champ d'activité"
R113: "Mathématiques du signal" R113: "Mathématiques du signal"
R114: "Mathématiques des transmissions" R114: "Mathématiques des transmissions"
@ -24,8 +24,8 @@ S2:
R207: "Sources de données" R207: "Sources de données"
R208: "Analyse et traitement de données structurées" R208: "Analyse et traitement de données structurées"
R209: "Initiation au développement Web" R209: "Initiation au développement Web"
R210: "Développement de l'anglais technique" R210: "Anglais de communication et développement de l'anglais technique"
R211: "Expression-Culture-Communication Professionnelles (ECC2)" R211: "Expression-Culture-Communication Professionnelles 2"
R212: "PPP: Formalisation du projet" R212: "PPP: Formalisation du projet"
R213: "Mathématiques des systèmes numériques" R213: "Mathématiques des systèmes numériques"
R214: "Analyse des signaux" R214: "Analyse mathématique des signaux"

View File

@ -1,12 +1,12 @@
S1: S1:
SAÉ11: "Réseaux / cybersécurité / hygiène informatique" SAÉ11: "Se sensibiliser à l'hygiène informatique et à la cybersécurité"
SAÉ12: "Réseau d'entreprise ou personnel" SAÉ12: "S'initier aux réseaux informatiques"
SAÉ13: "Supports de transmission / calculs" SAÉ13: "Découvrir un dispositif de transmission"
SAÉ14: "Se présenter sur Internet" SAÉ14: "Se présenter sur Internet"
SAÉ15: "Traiter des données" SAÉ15: "Traiter des données"
S2: S2:
SAÉ21: "Construction dun réseau informatique pour une petite structure" SAÉ21: "Construire un réseau informatique pour une petite structure"
SAÉ22: "Mesures et caractérisation dun signal ou dun système" SAÉ22: "Mesurer et caractériser un signal ou un système"
SAÉ23: "Mise en place d'une solution informatique pour lentreprise" SAÉ23: "Mettre en place une solution informatique pour lentreprise"
SAÉ24: "Projet intégratif de S2" SAÉ24: "Projet intégratif de S2"

View File

@ -1,7 +1,7 @@
import re import re
from officiel import * from officiel import *
from modeles import * from modeles import *
from officiel import supprime_accent_espace, get_code_from_nom from officiel import supprime_accent_espace, get_code_from_nom_using_dict
import ruamel.yaml import ruamel.yaml
from ruamel.yaml.scalarstring import FoldedScalarString as folded from ruamel.yaml.scalarstring import FoldedScalarString as folded
@ -10,9 +10,9 @@ __LOGGER = logging.getLogger(__name__)
class RessourceDocx(): class RessourceDocx():
"""Classe modélisant les ressources, lorsqu'elles sont extraites du docx""" """Classe modélisant les ressources, lorsqu'elles sont extraites du docx"""
def __init__(self, nom, brute): def __init__(self, nom, brut):
self.nom = nom self.nom = nom
self.brute = brute # les données brutes de la ressource self.brut = brut # les données brutes de la ressource
def charge_informations(self, code, semestre, heures_encadrees, tp, sae, prerequis, description, mots): def charge_informations(self, code, semestre, heures_encadrees, tp, sae, prerequis, description, mots):
self.code = code self.code = code
@ -64,26 +64,28 @@ class RessourceDocx():
output = output.replace("\n\n", "\n") output = output.replace("\n\n", "\n")
return output return output
def nettoie_heure(r): 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]))
def nettoie_heure_ressource(r):
"""Nettoie le champ (horaire) (de la forme 46h ou 33...) pour en extraire la valeur numérique : """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 le champ peut contenir 2 volumes (heures formation puis heures tp), auquel cas les 2 valeurs sont renvoyées
dans un tuple""" dans un tuple"""
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]))
if r.heures_encadrees: # si les heures encadrées sont renseignées if r.heures_encadrees: # si les heures encadrées sont renseignées
volumes = nettoie_champ_heure(r.heures_encadrees) volumes = nettoie_champ_heure(r.heures_encadrees)
if r.tp: if r.tp:
r.tp = nettoie_champ_heure(r.tp) r.tp = nettoie_champ_heure(r.tp)
if isinstance(volumes, int): if isinstance(volumes, int):
r.heures_encadrees = volumes r.heures_encadrees = volumes
elif isinstance(volumes, tuple): elif isinstance(volumes, tuple):
@ -97,11 +99,46 @@ def nettoie_heure(r):
#else: #else:
#__LOGGER.warning("Heures non détectées") #__LOGGER.warning("Heures non détectées")
def nettoie_code(r):
"""Recherche les codes ressources de la forme RXXX dans champ""" def nettoie_heure_sae(r):
"""Nettoie les champs (horaires) des saes"""
if r.heures_encadrees: # si les heures encadrées sont renseignées
r.heures_encadrees = nettoie_champ_heure(r.heures_encadrees)
else:
__LOGGER.warning(r"nettoie_heure_sae: dans {r.nom}, manque les heures de formation")
r.heures_encadrees = "???"
if r.tp:
r.tp = nettoie_champ_heure(r.tp)
else:
__LOGGER.warning(r"nettoie_heure_sae: dans {r.nom}, manque les heures de tp")
r.tp = "???"
if r.projet:
r.projet = nettoie_champ_heure(r.projet)
else:
__LOGGER.warning(r"nettoie_heure_sae: dans {r.nom}, manque les heures de projet")
r.projet = "???"
try:
if r.heures_encadrees < r.tp:
__LOGGER.warning(r"nettoie_heure_sae: dans {r.nom}, pb dans les heures formations/tp")
except:
pass
def nettoie_code(r, type = "ressource"):
"""Recherche les codes dans le champ:
* de la forme RXXX si type=ressource
* de la forme SAE|éXX si type=sae"""
champ = r.code champ = r.code
if r.code: if r.code:
codes = re.findall(r"(R[0-9][0-9][0-9])", champ) if type == "ressource":
codes = re.findall(r"(R[0-9][0-9][0-9])", champ)
else: # type = "sae"
codes = re.findall(r"(SAE[0-9][0-9]|SAÉ[0-9][0-9])", champ)
# ajout des É
codes = [c.replace("E", "É") for c in codes]
# if len(codes) > 1: # if len(codes) > 1:
# __LOGGER.warning("plusieurs codes trouvés :(") # __LOGGER.warning("plusieurs codes trouvés :(")
#elif len(codes) == 0: #elif len(codes) == 0:
@ -109,7 +146,10 @@ def nettoie_code(r):
if len(codes) == 1: if len(codes) == 1:
r.code = codes[0] r.code = codes[0]
else: else:
code_devine = get_code_from_nom(r) if type == "ressource":
code_devine = get_code_from_nom_using_dict(r, DATA_RESSOURCES)
else:
code_devine = get_code_from_nom_using_dict(r, DATA_SAES)
if code_devine: if code_devine:
__LOGGER.warning(f"nettoie_code : \"{r.nom}\" => code {code_devine}") __LOGGER.warning(f"nettoie_code : \"{r.nom}\" => code {code_devine}")
r.code = code_devine r.code = code_devine
@ -166,13 +206,21 @@ def nettoie_acs(r):
r.apprentissages = dico # [comp] = acs_finaux r.apprentissages = dico # [comp] = acs_finaux
def nettoie_sae(r): def nettoie_sae(r):
"""Nettoie les sae en détectant les codes""" """Nettoie le champ SAe d'une ressource en détectant les codes"""
SAE_avec_code = devine_sae_by_code(r.sae) SAE_avec_code = devine_sae_by_code(r.sae)
liste = [l.rstrip() for l in SAE_avec_code] liste = [l.rstrip() for l in SAE_avec_code]
r.sae = liste r.sae = liste
if not r.sae: if not r.sae:
__LOGGER.warning(f"nettoie_sae: dans {r.nom} pas de SAE (:") __LOGGER.warning(f"nettoie_sae: dans {r.nom} pas de SAE (:")
def nettoie_ressources(r):
"""Nettoie le champ ressource d'une sae en détectant les codes"""
ressources_avec_code = devine_ressources_by_code(r.ressources)
liste = [l.rstrip() for l in ressources_avec_code]
r.ressources = liste
if not r.ressources:
__LOGGER.warning(f"nettoie_ressources: dans {r.nom} pas de ressources (:")
def nettoie_prerequis(r): def nettoie_prerequis(r):
"""Nettoie les prérequis (ressource) en les remplaçant par leur code de ressource""" """Nettoie les prérequis (ressource) en les remplaçant par leur code de ressource"""
R_avec_code = devine_ressources_by_code(r.prerequis) R_avec_code = devine_ressources_by_code(r.prerequis)
@ -346,6 +394,40 @@ def caracteres_recalcitrants(contenu):
contenu = contenu.replace('\xa0', ' ') # le nbsp contenu = contenu.replace('\xa0', ' ') # le nbsp
return contenu return contenu
class SAEDocx():
def __init__(self, nom, brut):
self.nom = nom
self.brut = brut # les données brutes de la ressource
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
def charge_ac(self, apprentissages):
self.apprentissages = apprentissages
class ExempleSAEDocx():
def __init__(self, nom, brut):
self.nom = nom
self.brut = brut # les données brutes de la ressource
def charge_informations(self, description, formes, problematique, modalite):
self.description = description
self.formes = formes # <--
self.problematique = problematique
self.modalite = modalite
if __name__=="__main__": if __name__=="__main__":
# Eléments de test # Eléments de test
for sem in DATA_RESSOURCES: for sem in DATA_RESSOURCES:

19
python/tools.py Normal file
View File

@ -0,0 +1,19 @@
from officiel import supprime_accent_espace
def get_indice(champ, entetes):
"""Récupère l'indice d'une entête"""
for (i, entete) in enumerate(entetes):
if entete in champ:
return i
return None
def get_indice_sans_accent_ni_espace(champ, entetes):
"""Récupère l'indice d'une entête en se débarrassant des majuscules/caractères spéciaux/espace"""
champ_purge = supprime_accent_espace(champ).rstrip()
for (i, entete) in enumerate(entetes):
entete_purge = supprime_accent_espace(entete).rstrip()
if entete_purge in champ_purge:
return i
return None