forked from viennet/Referentiels
Ajout l'export yaml des ExemplesSAE
This commit is contained in:
parent
cef2735bfb
commit
a1cda41e51
@ -161,7 +161,7 @@
|
|||||||
|
|
||||||
|
|
||||||
% ****************************
|
% ****************************
|
||||||
% Déclaration de la ressource :
|
% Déclaration de la saé :
|
||||||
% \nouvellesae{code_sae}{intitule_sae}
|
% \nouvellesae{code_sae}{intitule_sae}
|
||||||
\def\nouvellesae#1#2{
|
\def\nouvellesae#1#2{
|
||||||
\addtocounter{cptsae}{1} % Ajoute une ressource (tous semestres confondu)
|
\addtocounter{cptsae}{1} % Ajoute une ressource (tous semestres confondu)
|
||||||
|
@ -23,7 +23,8 @@
|
|||||||
|
|
||||||
|
|
||||||
% Le description
|
% Le description
|
||||||
\ajoutSdescription{Il s'agit de faire prendre conscience aux étudiants les risques
|
\ajoutSdescription{
|
||||||
|
Il s'agit de faire prendre conscience aux étudiants les risques
|
||||||
potentiels pris par l'usager d'un environnement numérique et de leur
|
potentiels pris par l'usager d'un environnement numérique et de leur
|
||||||
fournir les réflexes afin de devenir un usager conscient, averti et
|
fournir les réflexes afin de devenir un usager conscient, averti et
|
||||||
responsable. L'hygiène informatique et les bonnes pratiques de l'usage
|
responsable. L'hygiène informatique et les bonnes pratiques de l'usage
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
% Ressources
|
% Ressources
|
||||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||||
|
|
||||||
\nouvellesae{SAÉ12}{S’initier aux réseaux informatiques}
|
\nouvellesae{SAÉ12}{S'initier aux réseaux informatiques}
|
||||||
|
|
||||||
\ajoutSheures{10}{7}{20}
|
\ajoutSheures{10}{7}{20}
|
||||||
|
|
||||||
|
@ -118,7 +118,7 @@ print(f"{nbre_ressources} ressources")
|
|||||||
ressources = {"S1" : [], "S2": []}
|
ressources = {"S1" : [], "S2": []}
|
||||||
|
|
||||||
for r in liste_ressources:
|
for r in liste_ressources:
|
||||||
nettoie_titre(r)
|
nettoie_titre_ressource(r)
|
||||||
nettoie_heure_ressource(r)
|
nettoie_heure_ressource(r)
|
||||||
nettoie_code(r, type="ressource")
|
nettoie_code(r, type="ressource")
|
||||||
nettoie_semestre(r)
|
nettoie_semestre(r)
|
||||||
|
@ -105,7 +105,7 @@ for i in range(1, len(docu)): # A priori un tableau
|
|||||||
r.charge_ac(apprentissages)
|
r.charge_ac(apprentissages)
|
||||||
|
|
||||||
# nettoie le titre et le code
|
# nettoie le titre et le code
|
||||||
nettoie_titre(r)
|
nettoie_titre_sae(r)
|
||||||
nettoie_code(r, type="sae")
|
nettoie_code(r, type="sae")
|
||||||
|
|
||||||
last_sae = r.code
|
last_sae = r.code
|
||||||
@ -116,7 +116,7 @@ for i in range(1, len(docu)): # A priori un tableau
|
|||||||
nom_exemple = res[0][1][0]
|
nom_exemple = res[0][1][0]
|
||||||
|
|
||||||
# Création de la ressource
|
# Création de la ressource
|
||||||
r = ExempleSAEDocx(nom_exemple, res)
|
r = ExempleSAEDocx(nom_exemple, res, last_sae)
|
||||||
liste_exemples[last_sae].append(r)
|
liste_exemples[last_sae].append(r)
|
||||||
|
|
||||||
# Parsing des données brute de la sae
|
# Parsing des données brute de la sae
|
||||||
@ -159,8 +159,10 @@ for s in liste_exemples:
|
|||||||
print(f"{s} :" + str(len(liste_exemples[s])) + " 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
|
# Post traitement des saes => gestion des heures/des acs/ + tri par semestre
|
||||||
|
print(" > SAE")
|
||||||
saes = {"S1" : [], "S2": []}
|
saes = {"S1" : [], "S2": []}
|
||||||
|
|
||||||
for s in liste_saes:
|
for s in liste_saes:
|
||||||
@ -176,7 +178,26 @@ for s in liste_saes:
|
|||||||
# Tri dans le bon semestre
|
# Tri dans le bon semestre
|
||||||
saes[s.semestre] += [s]
|
saes[s.semestre] += [s]
|
||||||
|
|
||||||
# # Export yaml
|
# 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}")
|
||||||
|
# nettoie_description(s) => rien à faire ?
|
||||||
|
nettoie_description(e)
|
||||||
|
nettoie_problematique(e)
|
||||||
|
if e.nom.startswith("Concevoir"):
|
||||||
|
print("ici")
|
||||||
|
nettoie_modalite(e)
|
||||||
|
|
||||||
|
# Tri dans le bon semestre
|
||||||
|
exemples[sem][s].append(e)
|
||||||
|
|
||||||
|
# Export yaml
|
||||||
|
print("*Etape 3* : Export yaml")
|
||||||
for sem in saes:
|
for sem in saes:
|
||||||
for s in saes[sem]:
|
for s in saes[sem]:
|
||||||
output = s.to_yaml()
|
output = s.to_yaml()
|
||||||
@ -185,3 +206,12 @@ for sem in saes:
|
|||||||
with open(fichier, "w", encoding="utf8") as fid:
|
with open(fichier, "w", encoding="utf8") as fid:
|
||||||
fid.write(output)
|
fid.write(output)
|
||||||
|
|
||||||
|
for sem in exemples:
|
||||||
|
for s in exemples[sem]:
|
||||||
|
for (i, e) in enumerate(exemples[sem][s]):
|
||||||
|
output = e.to_yaml()
|
||||||
|
fichier = "export/{}_exemple{}.yml".format(s.replace("É", "E"), i+1)
|
||||||
|
with open(fichier, "w", encoding="utf8") as fid:
|
||||||
|
fid.write(output)
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
from ressource import Ressource, SAE
|
from ressource import *
|
||||||
from ressourcedocx import *
|
import os
|
||||||
import pypandoc
|
import pypandoc
|
||||||
|
|
||||||
|
|
||||||
@ -27,12 +27,21 @@ fichiers = os.listdir(REPERTOIRE_RESSOURCES)
|
|||||||
fichiers = sorted(fichiers) # tri par ordre alphabétique
|
fichiers = sorted(fichiers) # tri par ordre alphabétique
|
||||||
|
|
||||||
saes = {"S1": [], "S2": []}
|
saes = {"S1": [], "S2": []}
|
||||||
|
exemples = {"S1" : {}, "S2" : {} }
|
||||||
|
|
||||||
for file in fichiers:
|
for file in fichiers:
|
||||||
fichieryaml = REPERTOIRE_RESSOURCES + "/" + file
|
fichieryaml = REPERTOIRE_RESSOURCES + "/" + file
|
||||||
if file.startswith("S"): # si c'est une sae
|
if file.startswith("S") and "exemple" not in file: # si c'est le chapeau d'une sae
|
||||||
s = SAE(fichieryaml)
|
s = SAE(fichieryaml)
|
||||||
sem = "S" + str(s.sae["semestre"])
|
sem = "S" + str(s.sae["semestre"])
|
||||||
saes[sem].append(s)
|
saes[sem].append(s)
|
||||||
|
elif file.startswith("S") and "exemple" in file: # si c'est un exemple de sae
|
||||||
|
e = ExempleSAE(fichieryaml)
|
||||||
|
sem = "S" + str(e.exemple["semestre"])
|
||||||
|
sae = e.exemple["code"]
|
||||||
|
if sae not in exemples[sem]:
|
||||||
|
exemples[sem][sae] = []
|
||||||
|
exemples[sem][sae].append(e)
|
||||||
|
|
||||||
# Eléments de tests
|
# Eléments de tests
|
||||||
r1 = ressources["S1"][0]
|
r1 = ressources["S1"][0]
|
||||||
|
@ -109,6 +109,7 @@ def get_officiel_sae_name_by_code(code):
|
|||||||
return get_officiel_name_by_code_using_dict(code, DATA_SAES)
|
return get_officiel_name_by_code_using_dict(code, DATA_SAES)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def get_code_from_nom_using_dict(ressource, dico):
|
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 si dico == DATA_RESSOURCES ; sinon fait de même avec les SAE"""
|
des ressources du yaml si dico == DATA_RESSOURCES ; sinon fait de même avec les SAE"""
|
||||||
@ -118,3 +119,9 @@ def get_code_from_nom_using_dict(ressource, dico):
|
|||||||
nom_data = supprime_accent_espace(dico[sem][code])
|
nom_data = supprime_accent_espace(dico[sem][code])
|
||||||
if nom.startswith(nom_data):
|
if nom.startswith(nom_data):
|
||||||
return code
|
return code
|
||||||
|
|
||||||
|
def get_officiel_sem_sae_by_code(sae):
|
||||||
|
"""Récupère le semestre de la SAE d'après son code"""
|
||||||
|
for sem in DATA_SAES:
|
||||||
|
if sae in DATA_SAES[sem]:
|
||||||
|
return sem
|
@ -106,7 +106,7 @@ class Ressource():
|
|||||||
|
|
||||||
|
|
||||||
class SAE():
|
class SAE():
|
||||||
"""Modélise une ressource lorsqu'elle est extraite d'un yaml"""
|
"""Modélise une saé (chapeau) lorsqu'elle est extraite d'un yaml"""
|
||||||
__LOGGER = logging.getLogger(__name__)
|
__LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
def __init__(self, fichieryaml):
|
def __init__(self, fichieryaml):
|
||||||
@ -139,6 +139,77 @@ class SAE():
|
|||||||
ressources = "\n".join(resRT)
|
ressources = "\n".join(resRT)
|
||||||
|
|
||||||
|
|
||||||
|
# préparation du descriptif
|
||||||
|
descriptif = self.sae["description"]
|
||||||
|
if descriptif == "Aucun":
|
||||||
|
descriptif = ""
|
||||||
|
SAE.__LOGGER.warning(f"{self.sae['titre']} n'a pas de description")
|
||||||
|
else:
|
||||||
|
descriptif = descriptif.replace("\n", "\n\n").replace("\n" * 4, "\n") # corrige les suppressions de ligne à la relecture du yaml
|
||||||
|
descriptif = md_to_latex(descriptif)
|
||||||
|
|
||||||
|
# préparation des livrables
|
||||||
|
livrables = self.sae["livrables"]
|
||||||
|
if livrables == "Aucun":
|
||||||
|
livrables = ""
|
||||||
|
SAE.__LOGGER.warning(f"{self.sae['titre']} n'a pas de livrables")
|
||||||
|
else:
|
||||||
|
livrables = livrables.replace("\n", "\n\n").replace("\n" * 4, "\n") # corrige les suppressions de ligne à la relecture du yaml
|
||||||
|
livrables = md_to_latex(livrables)
|
||||||
|
|
||||||
|
chaine = ""
|
||||||
|
chaine = TemplateLatex(modlatex).substitute(code=self.sae["code"],
|
||||||
|
titre=self.sae["titre"],
|
||||||
|
heures_encadrees=self.sae["heures_encadrees"],
|
||||||
|
heures_tp=self.sae["tp"],
|
||||||
|
heures_projet=self.sae["projet"],
|
||||||
|
compRT1=compRT[0],
|
||||||
|
compRT2=compRT[1],
|
||||||
|
compRT3=compRT[2],
|
||||||
|
description=caracteres_recalcitrants(descriptif),
|
||||||
|
ressources=ressources,
|
||||||
|
livrables= livrables,
|
||||||
|
motscles = caracteres_recalcitrants(self.sae["motscles"]),
|
||||||
|
)
|
||||||
|
# chaine = chaine.replace("&", "\&")
|
||||||
|
|
||||||
|
chaine = chaine.replace("\\tightlist\n", "")
|
||||||
|
return chaine
|
||||||
|
|
||||||
|
class ExempleSAE():
|
||||||
|
"""Modélise un exemple de SAE lorsqu'elle est extraite d'un yaml"""
|
||||||
|
__LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
def __init__(self, fichieryaml):
|
||||||
|
with open(fichieryaml, "r", encoding="utf8") as fid:
|
||||||
|
yaml = ruamel.yaml.YAML()
|
||||||
|
try:
|
||||||
|
self.exemple = yaml.load(fid.read())
|
||||||
|
except:
|
||||||
|
Ressource.__LOGGER.warning(f"Pb de chargement de {fichieryaml}")
|
||||||
|
|
||||||
|
def to_latex(self, modele="pn/modele_sae_exemple.tex"):
|
||||||
|
"""Génère le code latex décrivant la ressource"""
|
||||||
|
modlatex = get_modele(modele) #"pn/modele_ressource.tex")
|
||||||
|
|
||||||
|
# Préparation des ac
|
||||||
|
ajoutac = "\\ajoutSac{%s}{%s}"
|
||||||
|
compRT = []
|
||||||
|
for accomp in self.sae["acs"]:
|
||||||
|
comps = []
|
||||||
|
for no_ac in range(len(self.sae["acs"][accomp])): # les ac de la comp
|
||||||
|
code_ac = self.sae["acs"][accomp][no_ac]
|
||||||
|
comps.append( ajoutac % (code_ac, DATA_ACS[accomp][code_ac]) )
|
||||||
|
compRT.append("\n".join(comps))
|
||||||
|
|
||||||
|
# Préparation des ressources
|
||||||
|
ajoutressources = "\\ajoutSressources{%s}{%s}"
|
||||||
|
resRT = []
|
||||||
|
for (i, res) in enumerate(self.sae["ressources"]): # in range(len(self.apprentissages)):
|
||||||
|
resRT.append(ajoutressources % (res, get_officiel_ressource_name_by_code(res)))
|
||||||
|
ressources = "\n".join(resRT)
|
||||||
|
|
||||||
|
|
||||||
# préparation du descriptif
|
# préparation du descriptif
|
||||||
descriptif = self.sae["description"]
|
descriptif = self.sae["description"]
|
||||||
if descriptif == "Aucun":
|
if descriptif == "Aucun":
|
||||||
|
@ -160,8 +160,9 @@ def nettoie_semestre(r):
|
|||||||
__LOGGER.warning(f"nettoie_semestre : dans \"{r.nom}, PAS de semestre => rattaché au S2")
|
__LOGGER.warning(f"nettoie_semestre : dans \"{r.nom}, PAS de semestre => rattaché au S2")
|
||||||
r.semestre = "S2"
|
r.semestre = "S2"
|
||||||
|
|
||||||
def nettoie_titre(r):
|
def nettoie_titre_ressource(r):
|
||||||
"""Nettoie le titre en utilisant les titres officiels"""
|
"""Nettoie le titre d'une ressource en utilisant les titres officiels fournis dans le
|
||||||
|
yaml (via le dictionnaire DATA_RESSOURCES)"""
|
||||||
def devine_nom_from_ressources(champ):
|
def devine_nom_from_ressources(champ):
|
||||||
champ_purge = supprime_accent_espace(champ)
|
champ_purge = supprime_accent_espace(champ)
|
||||||
for sem in DATA_RESSOURCES:
|
for sem in DATA_RESSOURCES:
|
||||||
@ -173,9 +174,26 @@ def nettoie_titre(r):
|
|||||||
old = r.nom
|
old = r.nom
|
||||||
titre = devine_nom_from_ressources(r.nom)
|
titre = devine_nom_from_ressources(r.nom)
|
||||||
if titre and titre != old:
|
if titre and titre != old:
|
||||||
__LOGGER.warning(f"nettoie_titre : {old} => titre \"{titre}\"")
|
__LOGGER.warning(f"nettoie_titre_ressource : {old} => titre \"{titre}\"")
|
||||||
r.nom = titre
|
r.nom = titre
|
||||||
|
|
||||||
|
def nettoie_titre_sae(s):
|
||||||
|
"""Nettoie le titre d'une sae en utilisant les titres officiels fournis dans le
|
||||||
|
yaml (via le dictionnaire DATA_RESSOURCES)"""
|
||||||
|
def devine_nom_from_sae(champ):
|
||||||
|
champ_purge = supprime_accent_espace(champ)
|
||||||
|
for sem in DATA_SAES:
|
||||||
|
for code in DATA_SAES[sem]:
|
||||||
|
nom_purge = supprime_accent_espace(DATA_SAES[sem][code])
|
||||||
|
if champ_purge.startswith(nom_purge):
|
||||||
|
return DATA_SAES[sem][code] # le bon nom
|
||||||
|
|
||||||
|
old = s.nom
|
||||||
|
titre = devine_nom_from_sae(s.nom)
|
||||||
|
if titre and titre != old:
|
||||||
|
__LOGGER.warning(f"nettoie_titre_sae : {old} => titre \"{titre}\"")
|
||||||
|
s.nom = titre
|
||||||
|
|
||||||
def nettoie_acs(r):
|
def nettoie_acs(r):
|
||||||
"""Nettoie les acs d'une ressource en les remplaçant par leur code pour les 3 compétences"""
|
"""Nettoie les acs d'une ressource en les remplaçant par leur code pour les 3 compétences"""
|
||||||
if len(r.apprentissages) != 3:
|
if len(r.apprentissages) != 3:
|
||||||
@ -370,6 +388,8 @@ def convert_to_markdown(contenu):
|
|||||||
if m:
|
if m:
|
||||||
pos = marqueurs_finaux.index(m)
|
pos = marqueurs_finaux.index(m)
|
||||||
contenus_fin[i] = "\t" * (pos) + "* " + ligne.replace(m, "").replace("\t", "").rstrip()
|
contenus_fin[i] = "\t" * (pos) + "* " + ligne.replace(m, "").replace("\t", "").rstrip()
|
||||||
|
|
||||||
|
|
||||||
contenu = "\n\n".join(contenus_fin)
|
contenu = "\n\n".join(contenus_fin)
|
||||||
return contenu
|
return contenu
|
||||||
|
|
||||||
@ -388,6 +408,31 @@ def nettoie_livrables_sae(s):
|
|||||||
contenu = convert_to_markdown(contenu)
|
contenu = convert_to_markdown(contenu)
|
||||||
s.livrables = contenu
|
s.livrables = contenu
|
||||||
|
|
||||||
|
def nettoie_description(s):
|
||||||
|
"""Nettoie la description d'un exemple de SAE"""
|
||||||
|
contenu = s.description
|
||||||
|
contenu = remove_link(contenu) # supprime les liens
|
||||||
|
contenu = convert_to_markdown(contenu)
|
||||||
|
s.description = contenu
|
||||||
|
|
||||||
|
def nettoie_problematique(s):
|
||||||
|
"""Nettoie la description d'un exemple de SAE"""
|
||||||
|
if s.problematique:
|
||||||
|
contenu = s.problematique
|
||||||
|
contenu = convert_to_markdown(contenu)
|
||||||
|
s.problematique = contenu
|
||||||
|
else:
|
||||||
|
s.problematique = ""
|
||||||
|
|
||||||
|
def nettoie_modalite(s):
|
||||||
|
"""Nettoie les modalités (d'évaluation) d'un exemple de SAE"""
|
||||||
|
if s.modalite:
|
||||||
|
contenu = s.modalite
|
||||||
|
contenu = convert_to_markdown(contenu)
|
||||||
|
s.modalite = contenu
|
||||||
|
else:
|
||||||
|
s.modalite = f"Les même que les livrables et les productions de la {s.code}"
|
||||||
|
|
||||||
class SAEDocx():
|
class SAEDocx():
|
||||||
|
|
||||||
def __init__(self, nom, brut):
|
def __init__(self, nom, brut):
|
||||||
@ -405,6 +450,7 @@ class SAEDocx():
|
|||||||
self.livrables = livrables
|
self.livrables = livrables
|
||||||
self.mots = mots
|
self.mots = mots
|
||||||
|
|
||||||
|
|
||||||
def charge_ac(self, apprentissages):
|
def charge_ac(self, apprentissages):
|
||||||
self.apprentissages = apprentissages
|
self.apprentissages = apprentissages
|
||||||
|
|
||||||
@ -430,9 +476,12 @@ class SAEDocx():
|
|||||||
|
|
||||||
class ExempleSAEDocx():
|
class ExempleSAEDocx():
|
||||||
|
|
||||||
def __init__(self, nom, brut):
|
def __init__(self, nom, brut, code):
|
||||||
self.nom = nom
|
self.nom = nom
|
||||||
self.brut = brut # les données brutes de la ressource
|
self.brut = brut # les données brutes de la ressource
|
||||||
|
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])
|
||||||
|
|
||||||
def charge_informations(self, description, formes, problematique, modalite):
|
def charge_informations(self, description, formes, problematique, modalite):
|
||||||
self.description = description
|
self.description = description
|
||||||
@ -440,6 +489,20 @@ class ExempleSAEDocx():
|
|||||||
self.problematique = problematique
|
self.problematique = problematique
|
||||||
self.modalite = modalite
|
self.modalite = modalite
|
||||||
|
|
||||||
|
def to_yaml(self):
|
||||||
|
"""Exporte la ressource en yaml"""
|
||||||
|
dico = {"titre": self.nom,
|
||||||
|
"code": self.code,
|
||||||
|
"semestre": self.semestre,
|
||||||
|
"description": folded(self.description),
|
||||||
|
"formes": self.formes,
|
||||||
|
"problematique": folded(self.problematique),
|
||||||
|
"modalite": folded(self.modalite),
|
||||||
|
}
|
||||||
|
output = ruamel.yaml.dump(dico, Dumper=ruamel.yaml.RoundTripDumper,
|
||||||
|
allow_unicode=True, width=100)
|
||||||
|
output = output.replace("\n\n\n", "\n\n")
|
||||||
|
return output
|
||||||
|
|
||||||
if __name__=="__main__":
|
if __name__=="__main__":
|
||||||
# Eléments de test
|
# Eléments de test
|
||||||
|
@ -20,8 +20,10 @@ def get_indice_sans_accent_ni_espace(champ, entetes):
|
|||||||
|
|
||||||
|
|
||||||
def caracteres_recalcitrants(contenu):
|
def caracteres_recalcitrants(contenu):
|
||||||
contenu = contenu.replace("è", "è").replace(b"\xe2\x80\x99".decode("utf8"), "'").replace("é", "é")
|
contenu = contenu.replace("\'", "'")
|
||||||
contenu = contenu.replace("’", "'")
|
contenu = contenu.replace("è", "è")
|
||||||
|
contenu = contenu.replace("é", "é")
|
||||||
|
contenu = contenu.replace("’", "'").replace(b"\xe2\x80\x99".decode("utf8"), "'")
|
||||||
contenu = contenu.replace("â", "â").replace(b'a\xcc\x82'.decode("utf8"), "â")
|
contenu = contenu.replace("â", "â").replace(b'a\xcc\x82'.decode("utf8"), "â")
|
||||||
contenu = contenu.replace('\xa0', ' ') # le nbsp
|
contenu = contenu.replace('\xa0', ' ') # le nbsp
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user