Bonjour,
je voulais savoir s'il était possible d'agir au moment où l'utilisateur ferme la console Python liée à un script.
Version imprimable
Bonjour,
je voulais savoir s'il était possible d'agir au moment où l'utilisateur ferme la console Python liée à un script.
Le module atexit est peut-être ce que tu cherches.
Bonsoir,
La discussion n'est pas à mon niveau mais comme le sujet est sympa...
atexit n'est qu'une solution lorsque le script se termine normalement (de même que trace_variable sous Tkinter et consorts).
Dans le cadre d'un arrêt brusque (CTRL C, arrêt de python comme par un kill sous linux, etc...) je cherche encore. A mon niveau il ne me semble pas possible d'agir sur un code à partir de lui même.
Une idée (sous linux mais le principe est là) :
Toutefois si ce code lance un script indépendant en lui envoyant son pid en argv il est possible pour le script secondaire de vérifier si le script est actif/non actif mais pas terminé/non actif et terminé. Soit :
Pour le script principal
Lancement : Création du script secondaire et lui passe son pid en argv.
Actif : traitement et pid actif.
Planté : pas le temp de créer le fichier trace. pid n'existe plus et le fichier trace n'est pas créer.
Fin du script : Création du fichier trace dans le temp.
Pour le script secondaire
Actif : le pid existe
Non actif mais pas terminé : le pid n'existe plus mais le fichier trace de fin de script n'est pas crée. Relance du script et récup de son pid.
Non actif et fini : le pid existe et le fichier trace aussi : je supprime le fichier trace et tout le monde quitte.
Cela se complique si c'est pour un traitement, ce qui me semble est le cas. Dans ce cas la création d'un fichier avec le dernier élément traité ralenti énormément le code.
Voili, une idée au passage...
@+
Je ne savais pas que atexit ne gèrait pas les exceptions. A vrai dire, je ne me suis jamais penché sur ce module, mais mnt que tu le dis, ça me parait un comportement assez logique.
Il reste la solution du try/finally.
Code:
1
2
3
4
5
6
7
8 def main(): # du code if __name__ == "__main__": try: main() finally: # Code de finalisation
Bonjour,
Bien vu le finally. Sur un ctrl c cela fonctionne.
Par contre cela ne prend pas en compte une fermeture du shell (demande de rambc) ou un arrêt externe du script (kill/arrêt du processus).
Je parle dans le cadre :
Cela me semble un comportement normal. Dans le cadre d'un control c on demande l'arrêt du script et c'est intercepté. Les deux autres cas sont externes.Code:
1
2
3
4
5
6
7
8
9
10
11 def main(): a = 0 while a < 10000000000: a += 1 print a if __name__ == "__main__": try: main() finally: open("/tmp/fichiertrace", "w").write('fin')
Il ne reste donc plus que deux cas à gérer.
Bonne journée.
Je sais que ma solution est moche mais pour en finir avec mon pseudo qbasic et en complément de ce que je disais.
Le script principal écrit le script de contrôle dans le temporaire, le lance et le détruit en fin de traitement.
Le script de contrôle fais le vérification de fin normale sur sa propre présence.
Après tout se passe au niveau pid/argv.
Voila pour ce qui est du retour vers l'archéologie informatique et dans l'attente de lire une solution plus 'pro'.
@+
Petit edit explicatif :
Pour le script de contrôle
Si le pid existe et que le script de contrôle existe : fonctionnement normal
Si le pid n'existe plus et que le script de contrôle existe : il y a plantage > relance du script principal avec argv et arrêt du script de contrôle (puisque relancé par le principal)
Si le pid n'existe plus et le script non plus : fin
Le fait de faire un remove sur le script de contrôle n'empêche pas son fonctionnement.
@
Dernières news : Ma solution ne fonctionne pas non plus. Le script de contrôle utilise le même shell donc à la fermeture de celui-ci c'est la cascade...
@+
bonjour,
il reste toujours nohup pour rendre le script insensible à la fermeture du terminal shell (mais pas insensible à l'arrêt de la machine ;p)
sur Linux/Unix au moins je ne sais pas s'il y a l'équivalent sur Mac (probable) et sur win.
http://en.wikipedia.org/wiki/Nohup
une solution serait de lancer le script dans une console fille, ça n'empêcherait pas la fermeture mais ça pourrait l'intercepter (en bash ou en python) :
-on lance le script principale, genre : os.system('xterm -e "python mon_script"')
-os.system pause jusqu'à la fermeture de la console xterm
-traitement de la fermeture
CPython devrait interfacer tout les signaux unix et permettre de les traiter normalement. voir: http://www.python.org/doc/2.5.2/lib/module-signal.html
Mais je n'ai peut être pas tout compris?
atexit permet de déclarer les "callables" à exécuter lors d'une terminaison normale. Si la question est dans le cas ou la terminaison n'est pas normale...
si de toutes façons, il faut terminer, il va falloir passer par tout les callables déclarés par atexit - ou refaire l'équivalent de atexit, dommage-.
Donc, attraper le signal positionner un flag global disant 'sortie d'urgence' et sortir normalement pour passer par les atexit.
- W
Désolé wiztricks mais je n'arrive toujours pas à voir comment un code réagit à une intervention externe. Cela donne quoi en code ?
Bonsoir rambc,
Pas le temps ce soir mais voici un bout de code bidon (sans doute le pire) :
principal.py :
controle.py :Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45 #!/usr/bin/env python # -*- coding: UTF8 -*- # # from sys import argv import os.path from signal import SIGQUIT from subprocess import Popen, PIPE def VerifArg(): # Si il y a un argument c'est une relance try: if argv[1]: open('/tmp/fichiertrace', 'a').write('Relance de principal.py avec argument ' + argv[1] + os.linesep) return int(argv[1]) except: # Nettoyage utilisation précédente if os.path.isfile('/tmp/fichiertrace'): os.remove('/tmp/fichiertrace') if os.path.isfile("/tmp/fichiercount"): os.remove('/tmp/fichiercount') # Creation du log open('/tmp/fichiertrace', 'w').write('Premier lancement de principal.py' + os.linesep) return 0 def LanceControle(): # Lancement de control.py LanceControle = 'python ' + os.path.join(os.getcwd(), 'controle.py ' + str(os.getpid())) controle = Popen(LanceControle, shell=True) sts = os.waitpid(controle.pid, 1) open('/tmp/fichiertrace', 'a').write('Pid de principal.py : ' + str(os.getpid()) + os.linesep) open('/tmp/fichiertrace', 'a').write('Pid de controle.py : ' + str(controle.pid) + os.linesep) Count = VerifArg() LanceControle() # Traitement pour l'exemple while Count < 1000000: Count += 1 open('/tmp/fichiercount', 'w').write(str(Count)) # Fin de traitement open('/tmp/fichiercount', 'w').write('fin') open('/tmp/fichiertrace', 'a').write('Fin du traitement dans principal.py' + os.linesep) # Possible d'os.remove de controle.py s'il est créer par le principal open('/tmp/fichiertrace', 'a').write('Fin de principal.py' + os.linesep) os._exit(0)
Et son log :Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35 #!/usr/bin/env python # -*- coding: UTF8 -*- # # from sys import argv, stdout import os.path from time import sleep from subprocess import Popen, PIPE def Relance(count, MonPid): open('/tmp/fichiertrace', 'a').write("Erreur detectée : Relance de principal.py" + os.linesep + 'Avec pour argument count ' + str(count) + os.linesep) RelancePrincipal = 'python ' + os.path.join(os.getcwd(), 'principal.py ') + str(count) controle = Popen(RelancePrincipal, shell=True) sts = os.waitpid(controle.pid, 1) open('/tmp/fichiertrace', 'a').write('Fermeture de controle.py' + os.linesep) os._exit(0) open('/tmp/fichiertrace', 'a').write('Lancement de controle.py ' + os.linesep + 'Avec en argv le pid ' + str(argv[1]) + os.linesep) os.setsid() open('/tmp/fichiertrace', 'a').write('Changement de pid pour controle.py ' + '(' + str(os.getpid()) + ')' + os.linesep) attentefin = 'start' count = open('/tmp/fichiercount', 'r').read() while count != 'fin': Monps = Popen(['ps', '-e'], stdout=PIPE) Mongrep = Popen(['grep', str(argv[1])], stdin=Monps.stdout, stdout=PIPE) attentefin = Mongrep.communicate()[0] count = open('/tmp/fichiercount', 'r').read() if attentefin == '' and count != 'fin': Relance(count, os.getpid()) # sleep(50) # Fin de controle.py open('/tmp/fichiertrace', 'a').write('Fermeture de controle.py' + os.linesep) os._exit(0)
C'est plein de fautes mais cela semble fonctionner.Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 patrice@Zeus:~/Bureau$ cat /tmp/fichiertrace Premier lancement de principal.py Pid de principal.py : 29475 Pid de controle.py : 29476 Lancement de controle.py Avec en argv le pid 29475 Changement de pid pour controle.py (29477) Erreur detectée : Relance de principal.py <----Fermeture de la fenêtre. Avec pour argument count 32577 Relance de principal.py avec argument 32577 Fermeture de controle.py Pid de principal.py : 29839 Pid de controle.py : 29840 Lancement de controle.py Avec en argv le pid 29839 Changement de pid pour controle.py (29841) Fin du traitement dans principal.py Fin de principal.py Fermeture de controle.py patrice@Zeus:~/Bureau$
Reste à rajouter le try d'Antoine_935 pour le ctrl + c.
@+
Le post est allé au delà de ma question. Je reviendrais ici répondre plus tard car en ce moment je suis en plein passage de Python 26 à Python 3 et cela me pose quelques problèmes.
Et google?
regardez à : http://www.doughellmann.com/PyMOTW/signal/index.html
-W
Il est de notoriété que le novice.autodidacte utilise très mal ce moteur de recherche, surtout s'il n'a qu'une petite idée de ce qu'il recherche. Par contre avec un exemple c'est bien plus clair. Merci.
Le couple threading/signal fonctionne très bien pour ce qui est d'agir en cas de fermeture de la fenêtre.
Donc dans l'attente de savoir si c'est ce que recherche rambc.
Ps: Je n'étais pas si loin dans l'idée. threading > script / interception par signal > interruption donc plus de pid. Il ne me manque plus qu'à écrire en python.