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)
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
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 ?
@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
@Jérôme –
remplacer
inputFile= PdfFileReader(open(pdf, « rb »))
par
inputFile= PdfFileReader(open(pdf, « rb »),strict=False)