1
0
forked from ScoDoc/ScoDoc

WIP: nouveau format XML Orebut ref. comp.

This commit is contained in:
Emmanuel Viennet 2022-01-03 12:25:42 +01:00
parent e0be0f8fee
commit 407c3ef472
3 changed files with 39 additions and 7 deletions

View File

@ -29,8 +29,8 @@ def orebut_import_refcomp(xml_data: str, dept_id: int, orig_filename=None):
""" """
try: try:
root = ElementTree.XML(xml_data) root = ElementTree.XML(xml_data)
except ElementTree.ParseError: except ElementTree.ParseError as exc:
raise ScoFormatError("fichier XML Orébut invalide") raise ScoFormatError(f"fichier XML Orébut invalide (2): {exc.args}")
if root.tag != "referentiel_competence": if root.tag != "referentiel_competence":
raise ScoFormatError("élément racine 'referentiel_competence' manquant") raise ScoFormatError("élément racine 'referentiel_competence' manquant")
args = ApcReferentielCompetences.attr_from_xml(root.attrib) args = ApcReferentielCompetences.attr_from_xml(root.attrib)
@ -77,7 +77,8 @@ def orebut_import_refcomp(xml_data: str, dept_id: int, orig_filename=None):
a = ApcAnneeParcours(**ApcAnneeParcours.attr_from_xml(annee.attrib)) a = ApcAnneeParcours(**ApcAnneeParcours.attr_from_xml(annee.attrib))
parc.annees.append(a) parc.annees.append(a)
for competence in annee.findall("competence"): for competence in annee.findall("competence"):
nom = competence.attrib["nom"] nom_court = competence.attrib["nom_court"]
XXX
niveau = int(competence.attrib["niveau"]) niveau = int(competence.attrib["niveau"])
# Retrouve la competence # Retrouve la competence
comp = ref.competences.filter_by(titre=nom).all() comp = ref.competences.filter_by(titre=nom).all()

View File

@ -9,11 +9,24 @@ from datetime import datetime
from enum import unique from enum import unique
from typing import Any from typing import Any
from sqlalchemy.orm import class_mapper
import sqlalchemy
from app import db from app import db
from app.scodoc.sco_utils import ModuleType from app.scodoc.sco_utils import ModuleType
# from https://stackoverflow.com/questions/2537471/method-of-iterating-over-sqlalchemy-models-defined-columns
def attribute_names(cls):
"liste ids (noms de colonnes) d'un modèle"
return [
prop.key
for prop in class_mapper(cls).iterate_properties
if isinstance(prop, sqlalchemy.orm.ColumnProperty)
]
class XMLModel: class XMLModel:
_xml_attribs = {} # to be overloaded _xml_attribs = {} # to be overloaded
id = "_" id = "_"
@ -24,8 +37,12 @@ class XMLModel:
and renamed for our models. and renamed for our models.
The mapping is specified by the _xml_attribs The mapping is specified by the _xml_attribs
attribute in each model class. attribute in each model class.
Keep only attributes corresponding to columns in our model:
other XML attributes are simply ignored.
""" """
return {cls._xml_attribs.get(k, k): v for (k, v) in args.items()} columns = attribute_names(cls)
renamed_attributes = {cls._xml_attribs.get(k, k): v for (k, v) in args.items()}
return {k: renamed_attributes[k] for k in renamed_attributes if k in columns}
def __repr__(self): def __repr__(self):
return f'<{self.__class__.__name__} {self.id} "{self.titre if hasattr(self, "titre") else ""}">' return f'<{self.__class__.__name__} {self.id} "{self.titre if hasattr(self, "titre") else ""}">'
@ -34,11 +51,16 @@ class XMLModel:
class ApcReferentielCompetences(db.Model, XMLModel): class ApcReferentielCompetences(db.Model, XMLModel):
id = db.Column(db.Integer, primary_key=True) id = db.Column(db.Integer, primary_key=True)
dept_id = db.Column(db.Integer, db.ForeignKey("departement.id"), index=True) dept_id = db.Column(db.Integer, db.ForeignKey("departement.id"), index=True)
annexe = db.Column(db.Text())
specialite = db.Column(db.Text()) specialite = db.Column(db.Text())
specialite_long = db.Column(db.Text()) specialite_long = db.Column(db.Text())
type_titre = db.Column(db.Text()) type_titre = db.Column(db.Text())
type_structure = db.Column(db.Text())
type_departement = db.Column(db.Text()) # "secondaire", "tertiaire"
version_orebut = db.Column(db.Text())
_xml_attribs = { # Orébut xml attrib : attribute _xml_attribs = { # Orébut xml attrib : attribute
"type": "type_titre", "type": "type_titre",
"version": "version_orebut",
} }
# ScoDoc specific fields: # ScoDoc specific fields:
scodoc_date_loaded = db.Column(db.DateTime, default=datetime.utcnow) scodoc_date_loaded = db.Column(db.DateTime, default=datetime.utcnow)
@ -64,9 +86,13 @@ class ApcReferentielCompetences(db.Model, XMLModel):
""" """
return { return {
"dept_id": self.dept_id, "dept_id": self.dept_id,
"annexe": self.annexe,
"specialite": self.specialite, "specialite": self.specialite,
"specialite_long": self.specialite_long, "specialite_long": self.specialite_long,
"type_structure": self.type_structure,
"type_departement": self.type_departement,
"type_titre": self.type_titre, "type_titre": self.type_titre,
"version_orebut": self.version_orebut,
"scodoc_date_loaded": self.scodoc_date_loaded.isoformat() + "Z" "scodoc_date_loaded": self.scodoc_date_loaded.isoformat() + "Z"
if self.scodoc_date_loaded if self.scodoc_date_loaded
else "", else "",
@ -88,12 +114,14 @@ class ApcCompetence(db.Model, XMLModel):
referentiel_id = db.Column( referentiel_id = db.Column(
db.Integer, db.ForeignKey("apc_referentiel_competences.id"), nullable=False db.Integer, db.ForeignKey("apc_referentiel_competences.id"), nullable=False
) )
id_orebut = db.Column(db.Integer, nullable=True, index=True, unique=True)
titre = db.Column(db.Text(), nullable=False, index=True) titre = db.Column(db.Text(), nullable=False, index=True)
titre_long = db.Column(db.Text()) titre_long = db.Column(db.Text())
couleur = db.Column(db.Text()) couleur = db.Column(db.Text())
numero = db.Column(db.Integer) # ordre de présentation numero = db.Column(db.Integer) # ordre de présentation
_xml_attribs = { # xml_attrib : attribute _xml_attribs = { # xml_attrib : attribute
"name": "titre", "id": "id_orebut",
"nom_court": "titre", # was name
"libelle_long": "titre_long", "libelle_long": "titre_long",
} }
situations = db.relationship( situations = db.relationship(
@ -117,6 +145,7 @@ class ApcCompetence(db.Model, XMLModel):
def to_dict(self): def to_dict(self):
return { return {
"id_orebut": self.id_orebut,
"titre": self.titre, "titre": self.titre,
"titre_long": self.titre_long, "titre_long": self.titre_long,
"couleur": self.couleur, "couleur": self.couleur,

View File

@ -172,11 +172,13 @@ def refcomp_load(formation_id=None):
filename = secure_filename(f.filename) filename = secure_filename(f.filename)
try: try:
xml_data = f.read() xml_data = f.read()
ref = orebut_import_refcomp( _ = orebut_import_refcomp(
xml_data, dept_id=g.scodoc_dept_id, orig_filename=filename xml_data, dept_id=g.scodoc_dept_id, orig_filename=filename
) )
except TypeError as exc: except TypeError as exc:
raise ScoFormatError("fichier XML Orébut invalide") from exc raise ScoFormatError(
f"fichier XML Orébut invalide (1): {exc.args}"
) from exc
except ScoFormatError: except ScoFormatError:
raise raise