Envoie de sujets par mail avec AMC ?

A cause des réformes des retraites et des grèves qui ont suivi les examens sur table ont été annulés et ont été reprogrammé sous la forme d’un devoir à la maison.
Je devais donc envoyer mon QCM, élaboré avec auto-multiple-choice,  à un grand nombre de candidats. Je ne rentrerai pas ici dans l’intérêt de faire un examen QCM à domicile …

Avant de commencer noter que je suis sous Mac Os X Catalina.

Je fournis ici les scripts Python nécessaires pour :

  • Séparer le fichier PDF avec tous les sujets en autant de sujets qu’il y a de candidats
  • Envoyer les mails avec mutt (installer avec brew) à tous les candidats avec leurs fichiers en attachés

Mon sujet comporte 4 pages. Les N pdf individuels produits sont redirigés vers un dossier PDFSplitted. Je me suis basé sur cette page pour mon script.
Les noms de mes fichier se nomment : DOC-sujet1.pdf et DOC-sujet2.pdf.
Changer la variable « DOC-« +sujet+ ».pdf » en fonction du nom de votre sujet.

#!/usr/bin/env python

from PyPDF2 import PdfFileWriter, PdfFileReader
from multiprocessing import Pool
import glob, sys

sujet="sujet2"
pdfs = glob.glob("DOC-"+sujet+".pdf")

def process_pdfs(pdf):
    inputFile = PdfFileReader(open(pdf, "rb"))
    print("Processing %s"% pdf)
    for i in range(inputFile.numPages // 4):
        output = PdfFileWriter()
        output.addPage(inputFile.getPage(i * 4))
        output.addPage(inputFile.getPage(i * 4 + 1))
        output.addPage(inputFile.getPage(i * 4 + 2))
        output.addPage(inputFile.getPage(i * 4 + 3))

        newname = sujet + "-" + str(i+1) + ".pdf"

        outputStream = open("PDFSplitted/"+newname, "wb")
        output.write(outputStream)
        outputStream.close()

p = Pool(processes=4)
p.map(process_pdfs, pdfs)

Une fois les sujets produits je vais boucler sur l’ensemble des étudiants pour leur envoyer un mail (avec mutt) avec leur sujets individuels en attaché (il y a 2 sujets au choix).
La liste des étudiants avec leurs mails se trouve dans le fichier Emails-L2-1920.xlsx.
Je parse celui-ci avec xlrd.

import xlrd
import subprocess
import os

def body(*arg):
    mail_named="BodyMailStudents/"+str(arg[0]).replace(" ","-")+"-"+str(arg[1]).replace(" ","-")+"-N-"+str(arg[2])+".txt"
    fichier = open(mail_named, "w")
    temp=("Bonjour "+ str(arg[0])+ " " +str(arg[1]) + ",\n\n"\
            +"\t veuillez trouver en attaché de ce mail le sujet d'examen: MÉTHODES STATISTIQUES - PY03E300.\n"+\
            "Votre sujet n° " + str(arg[2]) +" est associé à votre numéro d'étudiant " + str(int(arg[3])) +".\n"\
            "Imprimez dans la mesure du possible votre copie en recto verso. Ne remplissez QUE L'UN DE CES DEUX SUJETS ET PAS UN AUTRE.\n"
            "Les copies doivent être rendues en mains propres à la scolarité entre le lundi 27 janvier\n"+\
            "et le jeudi 30 janvier en vous munissant de votre carte d’étudiant pour signer la feuille d’émargement.\n"\
            "Bon courage.\n\n"\
            "\n\t\t\t\t Cordialement,\n"\
            "\t\t\t\t\t Olivier Dadoun\n\n  ")         
    fichier.write(temp)
    fichier.close()
    print(temp)
    return mail_named

    
if __name__ == '__main__':           
    list_students="Emails-L2-1920.xlsx"
    wb = xlrd.open_workbook(list_students,encoding_override="utf_16_le")
    print(wb.sheet_names())
    sh = wb.sheet_by_name('Feuil3')
    num_etu          = sh.col_values(0)
    nom_pat_etu      = sh.col_values(1)
    prenom_etu       = sh.col_values(2)
    mail_etu         = sh.col_values(3)
    #list_pas_envoye=[18,30,40,41,44,45,51,56,57,100,101,102,103,109,115,119,128,158] 
    for i in range(1,len(num_etu)):
    #for i in list_pas_envoye:
        file_body=body(nom_pat_etu[i],prenom_etu[i],i,num_etu[i]) 
        files_attached1="\"PDFSplitted/sujet1-"+str(i)+".pdf\""
        files_attached2=files_attached1+" \"PDFSplitted/sujet2-"+str(i)+".pdf\""
        #mail="vous-aurez-pas-mon-mail@gmail.com"
        mail=mail_etu[i]
        mailcc="ni-celui-ci@gmail.com"
        bash_command="mutt -s \"Sujets d'examen MÉTHODES STATISTIQUES - PY03E300 \" " +  mail + " -c " + mailcc + " -a " + str(files_attached2)  + " -- < " + str(file_body)
        os.system(bash_command)
        print(bash_command)
        os.system("sleep 2")
    wb.release_resources()   

Si pour une raison inconnue l’étudiant n'a pas reçu son sujet on peut lui renvoyer car le corps du mail a été sauvé dans un fichier qui se trouve dans le dossier BodyMailStudents/.

Si cette erreur apparait avec votre pdf

PyPDF2.utils.PdfReadError: Multiple definitions in dictionary at byte 0x9af9 for key /AcroForm

Remplacer

inputFile= PdfFileReader(open(pdf, "rb"))

par

inputFile= PdfFileReader(open(pdf, "rb"),strict=False)
Ce contenu a été publié dans Python. Vous pouvez le mettre en favoris avec ce permalien.

4 réponses à Envoie de sujets par mail avec AMC ?

  1. Jérôme dit :

    Bonjour et merci pour cette contribution.
    Si je ne m’abuse, ce script ne conserve pas les « forms » dans le fichier pdf. Les élèves sont donc obligés d’imprimer, scanner et renvoyer les 4 images par mail. Ou alors c’est mon installation de PyPDF2 qui ne fonctionne pas bien ?
    Cordialement,
    Jérôme

    • admin dit :

      Bonjour,
      non non à priori il y a qu’un seul fichier pdf. J’avais 200 copies composées de 4 pages:
      output = PdfFileWriter()
      output.addPage(inputFile.getPage(i * 4))
      output.addPage(inputFile.getPage(i * 4 + 1))
      output.addPage(inputFile.getPage(i * 4 + 2))
      output.addPage(inputFile.getPage(i * 4 + 3))
      Ces lignes devraient faire un ficher pdf de 4 pages … ca n’est pas le cas ?

  2. Jérôme dit :

    @admin – Bonjour,
    je suis navré, j’ai dû penser à autre chose en écrivant, ma question n’est pas claire…
    Je recommence :
    mon objectif est d’envoyer par mail le sujet à chaque élève afin qu’il coche les cases du pdf. Je réalise un pdf QCM avec l’option [pdfform] d’AMC. Toutes les cases sont cliquables.
    Quand j’utilise ton script (ou bien pdftk), elles ne le sont plus.
    Je voulais savoir si c’était la même chose pour toi.
    Encore merci

  3. admin dit :

    @Jérôme
    remplacer
    inputFile= PdfFileReader(open(pdf, « rb »))
    par
    inputFile= PdfFileReader(open(pdf, « rb »),strict=False)

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *