Skip to main content

Access to ETNIC web services through Python

Project description

pyetnic

Bibliothèque Python d'accès aux services web SOAP d'ETNIC pour l'enseignement de promotion sociale (Wallonie-Bruxelles).

Fonctionnalités

Namespace Service Opérations
pyetnic.eprom Formations Lister les formations organisables (catalogue), lister les formations organisées
pyetnic.eprom Organisation Créer, lire, modifier, supprimer une organisation de formation
pyetnic.eprom Document 1 Lire, modifier, approuver le document de population (inscriptions)
pyetnic.eprom Document 2 Lire, modifier le document des périodes d'activités d'enseignement
pyetnic.eprom Document 3 Lire, modifier le document des attributions d'enseignants
pyetnic.seps Recherche étudiants Lire un étudiant par numéro CF, rechercher par NISS ou nom (prod uniquement)
pyetnic.seps Enregistrement étudiants Enregistrer un nouvel étudiant, modifier un étudiant existant (prod uniquement)
pyetnic.seps Inscriptions Rechercher, enregistrer, modifier des inscriptions d'étudiants (prod uniquement)

Installation

pip install pyetnic

Pour utiliser les services SEPS (signature X509) :

pip install pyetnic[seps]

Configuration

Générer un fichier .env de départ :

pyetnic init-config

Remplir les valeurs dans .env :

# Environnement : dev (services-web.tq.etnic.be) ou prod (services-web.etnic.be)
ENV=dev

# Identifiants pour le développement
DEV_USERNAME=
DEV_PASSWORD=

# Identifiants pour la production
PROD_USERNAME=
PROD_PASSWORD=

# Paramètres par défaut
DEFAULT_ETABID=       # identifiant établissement (int)
DEFAULT_IMPLID=       # identifiant implantation (int)
DEFAULT_SCHOOLYEAR=2024-2025

# Certificat X509 pour les services SEPS (chemin relatif au répertoire courant)
# Fourni par ETNIC (IAM-PROD). Uniquement nécessaire pour les services SEPS.
SEPS_PFX_PATH=
SEPS_PFX_PASSWORD=

Les identifiants EPROM sont fournis par ETNIC pour accéder aux services web de votre établissement. Le certificat SEPS (fichier .pfx) est fourni séparément par ETNIC via IAM-PROD.

Configuration programmatique

Pour les applications qui gèrent leurs propres credentials (ex. Django), il est possible de configurer pyetnic sans fichier .env :

from pyetnic.config import Config

Config.ENV = "prod"
Config.USERNAME = "my_user"
Config.PASSWORD = "my_pass"

# Optionnel : charger explicitement un fichier .env
Config.load_from_dotenv()

La configuration est lazy : rien n'est résolu à l'import. Les overrides programmatiques ont priorité sur les variables d'environnement.


Utilisation

Formations

import pyetnic

# Formations organisables (catalogue de l'année)
result = pyetnic.eprom.lister_formations_organisables(annee_scolaire="2024-2025")
for formation in result:
    print(formation.numAdmFormation, formation.codeFormation, formation.libelleFormation)

# Formations déjà organisées (avec leurs organisations et statuts de documents)
result = pyetnic.eprom.lister_formations(annee_scolaire="2024-2025")
for formation in result:
    for org in formation.organisations:
        print(
            f"F{org.id.numAdmFormation}/org{org.id.numOrganisation}",
            org.dateDebutOrganisation, "→", org.dateFinOrganisation,
            org.statutDocumentOrganisation.statut if org.statutDocumentOrganisation else "—",
        )

Organisation

from datetime import date
from pyetnic.eprom import OrganisationId, lire_organisation, creer_organisation
from pyetnic.eprom import modifier_organisation, supprimer_organisation

org_id = OrganisationId(
    anneeScolaire="2024-2025",
    etabId=3052,
    numAdmFormation=455,
    numOrganisation=1,
)

# Lire
org = lire_organisation(org_id)

# Créer (numOrganisation attribué par le serveur)
org = creer_organisation(
    annee_scolaire="2025-2026",
    etab_id=3052,
    impl_id=6050,
    num_adm_formation=455,
    date_debut=date(2025, 9, 15),
    date_fin=date(2026, 6, 26),
)

# Modifier
org.dateFinOrganisation = date(2026, 6, 20)
org = modifier_organisation(org)

# Supprimer
ok = supprimer_organisation(org_id)

Document 1 — Population

from pyetnic.eprom import lire_document_1, modifier_document_1, approuver_document_1
from pyetnic.eprom import Doc1PopulationListSave, Doc1PopulationLineSave

doc1 = lire_document_1(org_id)
# doc1 est None si le document n'est pas accessible (statut org insuffisant)

# Modifier
liste_save = Doc1PopulationListSave(population=[
    Doc1PopulationLineSave(coAnnEtude=1, nbEleveA=12, nbEleveTotHom=5, nbEleveTotFem=7),
])
doc1 = modifier_document_1(org_id, population_liste=liste_save)

# Approuver
doc1 = approuver_document_1(org_id)

Document 2 — Périodes d'activités

from pyetnic.eprom import lire_document_2, modifier_document_2
from pyetnic.eprom import Doc2ActiviteEnseignementListSave, Doc2ActiviteEnseignementLineSave

doc2 = lire_document_2(org_id)

liste_save = Doc2ActiviteEnseignementListSave(activiteEnseignement=[
    Doc2ActiviteEnseignementLineSave(coNumBranche=1, nbEleveC1=15, nbPeriodePrevueAn1=32.0),
])
doc2 = modifier_document_2(org_id, activite_enseignement_liste=liste_save)

Document 3 — Attributions d'enseignants

from pyetnic.eprom import (
    lire_document_3, modifier_document_3,
    Doc3ActiviteListeSave, Doc3ActiviteDetailSave,
    Doc3EnseignantListSave, Doc3EnseignantDetailSave,
)

doc3 = lire_document_3(org_id)
# doc3 est None si Doc 1 et Doc 2 ne sont pas encore approuvés

liste_save = Doc3ActiviteListeSave(activite=[
    Doc3ActiviteDetailSave(
        coNumBranche=1,
        noAnneeEtude="1",
        enseignantListe=Doc3EnseignantListSave(enseignant=[
            Doc3EnseignantDetailSave(
                coNumAttribution=1,
                noMatEns="28901061314",
                teStatut="T",
                nbPeriodesAttribuees=52.0,
            )
        ]),
    ),
])
doc3 = modifier_document_3(org_id, liste_save)

SEPS — Recherche et enregistrement d'étudiants

Prérequis : pip install pyetnic[seps] + certificat .pfx fourni par ETNIC (IAM-PROD). Ces services fonctionnent uniquement en production (ws.etnic.be).

from pyetnic.seps import (
    rechercher_etudiants, lire_etudiant,
    enregistrer_etudiant, modifier_etudiant,
    EtudiantDetailsSave, SepsNaissanceSave, SepsAdresseSave,
    NissMutationError,
)

# Recherche par nom
etudiants = rechercher_etudiants(nom="DUPONT", prenom="Jean")
for e in etudiants:
    details = e.rnDetails or e.cfwbDetails
    if details:
        print(e.cfNum, details.nom, details.prenom, details.naissance.date if details.naissance else "")

# Recherche par NISS (avec gestion de mutation)
try:
    etudiants = rechercher_etudiants(niss="850101-123-45")
except NissMutationError as e:
    etudiants = rechercher_etudiants(niss=e.nouveau_niss)

# Lecture par numéro CF (format : [0-9]{1,10}-[0-9]{2})
etudiant = lire_etudiant("12345678-01")
if etudiant:
    rn = etudiant.rnDetails
    print(rn.nom, rn.prenom, rn.niss)

# Enregistrement d'un étudiant (mode DETAILS = recherche par identité)
details = EtudiantDetailsSave(
    nom="DUPONT",
    prenom="Jean",
    sexe="M",
    naissance=SepsNaissanceSave(date="1985-01-15", codePays="BE"),
)
etudiant = enregistrer_etudiant("DETAILS", etudiant_details=details)

# Modification d'un étudiant existant
etudiant = modifier_etudiant("12345678-01", etudiant_details=EtudiantDetailsSave(
    adresse=SepsAdresseSave(rue="Rue de la Paix", codePostal="1000", codePays="BE"),
))

SEPS — Inscriptions

from pyetnic.seps import (
    rechercher_inscriptions, enregistrer_inscription, modifier_inscription,
    InscriptionInputDataSave, InscriptionInputSave, SepsUESave, SepsSpecificiteSave,
    SepsDroitInscriptionSave, SepsAdmissionSave, SepsSanctionSave,
)

# Recherche des inscriptions d'un étudiant
inscriptions = rechercher_inscriptions(cf_num="12345678-01", annee_scolaire=2024)
for i in inscriptions:
    print(i.cfNum, i.anneeScolaire, i.statut, i.ue.noAdministratif if i.ue else "")

# Enregistrement d'une nouvelle inscription
data = InscriptionInputDataSave(
    cfNum="12345678-01",
    idEtab=3052,
    idImplantation=6050,
    codePostalLieuCours="4000",
    inscription=InscriptionInputSave(
        dateInscription="2024-09-15",
        statut="I",
        ue=SepsUESave(noAdministratif=455, noOrganisation=1),
    ),
)
inscription = enregistrer_inscription(inscription_input_data=data)

# Modification d'une inscription existante
inscription = modifier_inscription(inscription_input_data=data)

Workflow métier

Les documents suivent un workflow séquentiel imposé par ETNIC :

Créer organisation  →  statut "Encodé école"
        ↓
Inspection approuve →  statut "Approuvé"
        ↓
Doc 1 accessible (lecture/modification/approbation)
        ↓
Doc 2 accessible (lecture/modification)
        ↓
Doc 1 ET Doc 2 approuvés  →  Doc 3 accessible

Règles de blocage :

  • Doc 1 : inaccessible si l'organisation est "Encodé école"
  • Doc 3 : nécessite que Doc 1 et Doc 2 soient approuvés (erreur ETNIC 20102)
  • L'approbation de l'organisation est effectuée par l'inspection, pas par l'école

Modèles de données

Identifiant d'organisation

from pyetnic.eprom import OrganisationId

org_id = OrganisationId(
    anneeScolaire="2024-2025",  # ex. "2024-2025"
    etabId=3052,                # identifiant établissement
    numAdmFormation=455,        # numéro administratif de la formation
    numOrganisation=1,          # numéro d'organisation (attribué par le serveur à la création)
    # implId : présent dans les réponses serveur, NE PAS inclure dans les requêtes
)

Important : implId est retourné par le serveur mais ne doit pas être envoyé dans les requêtes Lire/Modifier/Supprimer. Seul creer_organisation accepte impl_id.

Vue d'une organisation

OrganisationApercu (retourné par lister_formations) contient les statuts des 4 documents :

Champ Description
statutDocumentOrganisation Statut de l'organisation elle-même
statutDocumentPopulationPeriodes Statut du Document 1
statutDocumentDroitsInscription Statut du Document droits d'inscription
statutDocumentAttributions Statut du Document 3

Organisation (retourné par lire_organisation) hérite de OrganisationApercu et ajoute les champs métier complets. Note : les champs statutDocument* sont toujours None dans Organisation — ils ne sont disponibles que via lister_formations.


Gestion des erreurs

Toutes les fonctions de service retournent None (plutôt qu'une exception) si :

  • Le serveur répond avec success: False (accès refusé, document non existant, workflow non respecté, etc.)
  • Le document n'est pas accessible selon le workflow métier

Les erreurs réseau et SOAP sont encapsulées dans SoapError et propagées.

Codes d'erreur ETNIC courants :

Code Description
00009 Aucun enregistrement trouvé
20102 Doc 1 et Doc 2 doivent être approuvés pour accéder au Doc 3
SECU-0104 Certificat X509 non enregistré dans l'annuaire (SEPS en dev)

Structure du projet

pyetnic/
├── __init__.py                  # Point d'entrée : from . import eprom, seps
├── eprom/
│   └── __init__.py              # Namespace public EPROM (fonctions + modèles)
├── seps/
│   └── __init__.py              # Namespace public SEPS (fonctions + modèles)
├── cli.py                       # CLI : commande init-config
├── config.py                    # Configuration (.env, endpoints SOAP)
├── soap_client.py               # SoapClientManager (zeep + WSSE/X509)
├── services/                    # Implémentation interne
│   ├── models.py                # Tous les dataclasses
│   ├── formations_liste.py
│   ├── organisation.py
│   ├── document1.py
│   ├── document2.py
│   ├── document3.py
│   ├── seps.py
│   ├── enregistrer_etudiant.py
│   └── inscriptions.py
└── resources/
    ├── EPROM_Formations_Liste_2.0/
    ├── EPROM_Formation_Organisation_7.0/
    ├── EPROM_Formation_Population_1.0/
    ├── EPROM_Formation_Periodes_1.0/
    ├── EPROM_Document_3_1.0/
    ├── SEPS_Recherche_Etudiants_2.1/
    ├── SEPS_Enregistrer_Etudiant_2.1/
    ├── SEPS_Enregistrer_Inscription_2.1/
    └── SEPS_Recherche_Inscriptions_2.1/

Tests

# Tous les tests (mock + intégration)
pytest tests/

# Mock uniquement (sans credentials)
pytest tests/ -k "mock"

Les tests d'intégration nécessitent un .env valide. Ils skipent automatiquement si les credentials sont absents ou si le document n'est pas accessible dans l'environnement courant.

Environnements ETNIC :

  • devservices-web.tq.etnic.be / ws-tq.etnic.be (test, SSL non vérifié)
  • prodservices-web.etnic.be / ws.etnic.be (production, SSL vérifié)

Dépendances

Package Usage
zeep Client SOAP
python-dotenv Chargement .env
requests Transport HTTP
cryptography Extraction PFX en mémoire (SEPS)
openpyxl Export Excel
xmlsec (extra seps) Signature XML X509

Licence

MIT — voir LICENSE

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pyetnic-0.0.12.tar.gz (89.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pyetnic-0.0.12-py3-none-any.whl (121.0 kB view details)

Uploaded Python 3

File details

Details for the file pyetnic-0.0.12.tar.gz.

File metadata

  • Download URL: pyetnic-0.0.12.tar.gz
  • Upload date:
  • Size: 89.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for pyetnic-0.0.12.tar.gz
Algorithm Hash digest
SHA256 f5f4eaf45d9e7145b23707854be8ec6cc051d336d8230432a58c6926a1208169
MD5 42631d6148da4aad702fab5089e81ae6
BLAKE2b-256 08b1942e8d3d7c0ebd7963dd52c46f0cc7af1ae7a19d692c118a99901c6040f6

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyetnic-0.0.12.tar.gz:

Publisher: publish-pypi.yml on Lapin-Blanc/pyetnic

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file pyetnic-0.0.12-py3-none-any.whl.

File metadata

  • Download URL: pyetnic-0.0.12-py3-none-any.whl
  • Upload date:
  • Size: 121.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for pyetnic-0.0.12-py3-none-any.whl
Algorithm Hash digest
SHA256 7939803813408253693792df14402a521cf91282bb53ef63ec4bf7bc2ef1a02e
MD5 0dbe885ea0464ea92aa2671b8b2c4dd0
BLAKE2b-256 2cbf06b521c12fc4c84096dc271299301fe9e3cb32f787f384cf9e972da788da

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyetnic-0.0.12-py3-none-any.whl:

Publisher: publish-pypi.yml on Lapin-Blanc/pyetnic

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page