IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Python Discussion :

Récupérer la sortie du terminal (stdout je crois) dans une GUI ?


Sujet :

Python

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    Inscrit en
    Novembre 2007
    Messages
    66
    Détails du profil
    Informations forums :
    Inscription : Novembre 2007
    Messages : 66
    Par défaut Récupérer la sortie du terminal (stdout je crois) dans une GUI ?
    Salut à tous !

    Je suis en train de me coder un petit script python avec une GUI en wxPython (mais la GUI n'a aucun intérêt ici, on pourrait aussi bien le faire avec Tkinter, PyQt...).
    Dans ce script, j’exécute une commande externe très longue à exécuter et très bavarde !
    Genre rsync.

    Je voudrais savoir comment faire pour récupérer ce que cette commande affiche dans le terminal au fur et à mesure.
    J'ai testé os.system() et os.popen(), mais tout deux me retourne le résultat une fois l’exécution de la commande terminé !
    Je voudrais pouvoir l'afficher en temps réel, dans une zone de texte par exemple.

    J'ai chercher sur Google, mais j'ai rien trouvé en pur python, que des truc Perl...

    Est-ce que c'est faisable ?

    Merci d'avance !

  2. #2
    Expert confirmé

    Homme Profil pro
    Inscrit en
    Octobre 2008
    Messages
    4 307
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Octobre 2008
    Messages : 4 307
    Par défaut
    Salut,

    J'ai obtenu ce résultat avec ce code :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
     
        def get_images(self, rep, bind, r=None):
                reply = subprocess.Popen(["gphoto2", "--get-file", r], 
                                        universal_newlines=True,
                                        stdout=subprocess.PIPE)
     
                while 1:
                    #The two last characters are '\n'
                    text = reply.stdout.readline()[:-2]
                    if type(text) != str or text == '' and reply.poll() != None: 
                        break
                    elif type(text) == str and len(text) > 6:
                        # !!The next two lines are specific for Qt widget
                        bind.appendPlainText(text)
                        QtCore.QCoreApplication.processEvents()
    Donc, en détail, j'utilise gPhoto2 qui importe des photos d'un appareil numérique et je voulais avoir comme toi les progrès dans l'interface de mon appli et pas dans la console.

    Dans les arguments, celui qui t'intéresse est 'bind', il s'agit de l'instance du plainText de mon appli, les deux dernières lignes lui envoient le texte, tu adapteras en fonction de ton widget texte.

    Ce n'est pas non plus garantit avec tout les process, j'ai essayé la même chose avec la librairie dcraw qui est aussi un frontend en ligne de commande et ça ne fonctionne pas.

  3. #3
    Membre confirmé
    Inscrit en
    Novembre 2007
    Messages
    66
    Détails du profil
    Informations forums :
    Inscription : Novembre 2007
    Messages : 66
    Par défaut
    Je teste ça dès que j'ai un petit moment et je te tiens au courrant !
    Merci VinsS !

  4. #4
    Membre confirmé
    Inscrit en
    Novembre 2007
    Messages
    66
    Détails du profil
    Informations forums :
    Inscription : Novembre 2007
    Messages : 66
    Par défaut
    Voilà, je viens de tester :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
     
    import wx
    import subprocess
    import threading
     
    class WorkerTread (threading.Thread):
    	def __init__ (self, window):
    		threading.Thread.__init__(self)
     
    		self.window = window
    		self.start()
     
    	def run (self):
    		self.reply = subprocess.Popen(["ping", "google.com"], universal_newlines=True, stdout=subprocess.PIPE)
    		while True:
    			texte = self.reply.stdout.readline()
    			if type(texte) == str:
    				wx.CallAfter(self.window.textCtrl_append, texte)
     
    	def stop (self):
    		self.reply.kill()
     
    class Gui (wx.Frame):
    	def __init__ (self, titre):
    		self.titre = titre
     
    		wx.Frame.__init__(self, None, wx.ID_ANY, title=self.titre)
    		sizer = wx.GridBagSizer()
     
    		# ----------------------------------------------------------------------------------------------------------- Champ de texte
     
    		self.textCtrl = wx.TextCtrl(self, wx.ID_ANY, size=(800, 600), style=wx.TE_MULTILINE|wx.TE_READONLY)
    		self.textCtrl.SetBackgroundColour('#000000')
    		self.textCtrl.SetForegroundColour('#ffffff')
     
    		sizer.Add(self.textCtrl, (0, 0), flag=wx.EXPAND|wx.ALL, border=10)
     
    		# ----------------------------------------------------------------------------------------------------------- Boutons Quitter...
     
    		buttonExit = wx.Button(self, wx.ID_EXIT)
    		sizer.Add(buttonExit, (1, 0), flag=wx.ALIGN_CENTRE|wx.BOTTOM, border=10)
     
    		# ----------------------------------------------------------------------------------------------------------- Divers
     
    		# Initialisation
    		self.thread = WorkerTread(self)
     
    		# Sizer + Fit
    		self.SetSizerAndFit(sizer)
    		self.Fit()
     
    		# Non redimentionnable
    		self.SetMinSize(self.GetSize())
    		sizer.AddGrowableCol(0)
    		sizer.AddGrowableRow(0)
     
    		# Evénements
    		self.Bind(wx.EVT_BUTTON, self.exit, buttonExit)
     
    	# ----------------------------------------------------------------------------------------------------------- Fonctions Générales
     
    	def textCtrl_append (self, texte):
    		self.textCtrl.AppendText(texte)
     
    	def exit (self, event):
    		self.thread.stop()
    		self.Close()
     
    class Ihm (wx.App):
    	def OnInit (self):
    		root = Gui(u'stdout')
    		root.Show(True)
    		self.SetTopWindow(root)
    		return True
     
    if __name__ == '__main__':
    	app = Ihm()
    	app.MainLoop()
    Ça marche super :


    Petit bémol en revanche.
    Quand je clique su mon bouton "Quitter", l'application ne se ferme pas, je suis obligé de faire "Ctrl+c" dans le terminal.
    Je suppose qu'il faut tuer le subprocess.
    J'ai essayé avec Popen.kill() comme je l'ai vu dans la Doc...
    Mais rien à faire !

    Comment faire ?

    Merci VinsS !

  5. #5
    Expert confirmé

    Homme Profil pro
    Inscrit en
    Octobre 2008
    Messages
    4 307
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Octobre 2008
    Messages : 4 307
    Par défaut
    Euh, ... non, normalement subprocess est mort lorsque sa tâche est terminée.

    Si tu remplace 'self.close()' par 'sys.exit()', ça va pas mieux ?

  6. #6
    Membre confirmé
    Inscrit en
    Novembre 2007
    Messages
    66
    Détails du profil
    Informations forums :
    Inscription : Novembre 2007
    Messages : 66
    Par défaut
    Non, toujours pareil !

  7. #7
    Membre confirmé
    Inscrit en
    Novembre 2007
    Messages
    66
    Détails du profil
    Informations forums :
    Inscription : Novembre 2007
    Messages : 66
    Par défaut
    Encore un peu plus propre/optimisé :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
     
    import wx
    import subprocess
    import threading
    import sys
     
    class WorkerTread (threading.Thread):
    	def __init__ (self, window):
    		self.window = window
     
    		threading.Thread.__init__(self)
    		self.start()
     
    	def run (self):
    		self.reply = subprocess.Popen(["ping", "google.com"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
     
    		ligne = self.reply.stdout.readline()
    		while ligne:
    			wx.CallAfter(self.window.textCtrl_append, ligne)
    			sys.stdout.flush()
    			ligne = self.reply.stdout.readline()
     
    	def stop (self):
    		self.reply.kill()
     
    class Gui (wx.Frame):
    	def __init__ (self, titre):
    		self.titre = titre
     
    		wx.Frame.__init__(self, None, wx.ID_ANY, title=self.titre)
    		sizer = wx.GridBagSizer()
     
    		# ----------------------------------------------------------------------------------------------------------- Champ de texte
     
    		self.textCtrl = wx.TextCtrl(self, wx.ID_ANY, size=(800, 600), style=wx.TE_MULTILINE|wx.TE_READONLY)
    		self.textCtrl.SetBackgroundColour('#000000')
    		self.textCtrl.SetForegroundColour('#ffffff')
     
    		sizer.Add(self.textCtrl, (0, 0), flag=wx.EXPAND|wx.ALL, border=10)
     
    		# ----------------------------------------------------------------------------------------------------------- Boutons Quitter...
     
    		buttonExit = wx.Button(self, wx.ID_EXIT)
    		sizer.Add(buttonExit, (1, 0), flag=wx.ALIGN_CENTRE|wx.BOTTOM, border=10)
     
    		# ----------------------------------------------------------------------------------------------------------- Divers
     
    		# Initialisation
    		self.thread = WorkerTread(self)
     
    		# Sizer + Fit
    		self.SetSizerAndFit(sizer)
    		self.Fit()
     
    		# Non redimentionnable
    		self.SetMinSize(self.GetSize())
    		sizer.AddGrowableCol(0)
    		sizer.AddGrowableRow(0)
     
    		# Evénements
    		self.Bind(wx.EVT_BUTTON, self.exit, buttonExit)
    		self.Bind(wx.EVT_CLOSE, self.post_exit)
     
    	# ----------------------------------------------------------------------------------------------------------- Fonctions Générales
     
    	def textCtrl_append (self, texte):
    		self.textCtrl.AppendText(texte)
     
    	def post_exit (self, event):
    		self.thread.stop()
    		self.Destroy()
     
    	def exit (self, event):
    		self.Close()
     
    class Ihm (wx.App):
    	def OnInit (self):
    		root = Gui(u'stdout')
    		root.Show(True)
    		self.SetTopWindow(root)
    		return True
     
    if __name__ == '__main__':
    	app = Ihm()
    	app.MainLoop()
    Mais comme tu m'as dis VinsS, ça ne marche pas tout le temps !
    J'ai essayé de remplacer le ping par la commande "tree" (Linux), ça n'affiche rien, et ça bloque la fermeture du programme.

  8. #8
    Expert confirmé

    Homme Profil pro
    Inscrit en
    Octobre 2008
    Messages
    4 307
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Octobre 2008
    Messages : 4 307
    Par défaut
    Mais tu as toujours ta ligne reply.kill() et tes fonctions stop () et post_exit() qui ne servent à rien.

    Je pensais aussi que tu voulais vraiment pinger plusieurs fois de suite.

    Alors on peut simplifier tout ça:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
     
    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
     
    import sys
    import wx
    import subprocess
    import threading
    import time
     
    class WorkerTread (threading.Thread):
        def __init__ (self, window):
            threading.Thread.__init__(self)
     
            self.window = window
     
        def run (self):
            reply = subprocess.Popen(["ping", "google.com"], universal_newlines=True,
                                            stdout=subprocess.PIPE)
            while True:
                texte = reply.stdout.readline()
                if type(texte) == str:
                    wx.CallAfter(self.window.textCtrl_append, texte)
                    break
     
     
    class Gui (wx.Frame):
        def __init__ (self, titre):
            self.titre = titre
     
            wx.Frame.__init__(self, None, wx.ID_ANY, title=self.titre)
            sizer = wx.GridBagSizer()
     
            # ---------------Champ de texte
     
            self.textCtrl = wx.TextCtrl(self, wx.ID_ANY, size=(800, 600), 
                                                 style=wx.TE_MULTILINE|wx.TE_READONLY)
            self.textCtrl.SetBackgroundColour('#000000')
            self.textCtrl.SetForegroundColour('#ffffff')
     
            sizer.Add(self.textCtrl, (0, 0), flag=wx.EXPAND|wx.ALL, border=10)
     
            # ------------- Boutons Quitter...
     
            buttonExit = wx.Button(self, wx.ID_EXIT)
            sizer.Add(buttonExit, (1, 0), flag=wx.ALIGN_CENTRE|wx.BOTTOM, border=10)
     
            # ------Divers
     
            # Initialisation
            self.thread = WorkerTread(self)
            self.thread.start()
     
            # Sizer + Fit
            self.SetSizerAndFit(sizer)
            self.Fit()
     
            # Non redimentionnable
            self.SetMinSize(self.GetSize())
            sizer.AddGrowableCol(0)
            sizer.AddGrowableRow(0)
     
            # Evénements
            self.Bind(wx.EVT_BUTTON, self.close, buttonExit)
     
            # -------Fonctions Générales
     
        def textCtrl_append (self, texte):
            self.textCtrl.AppendText(texte)
     
        def close(self, event):
            self.Close()
     
    class Ihm (wx.App):
        def OnInit (self):
            root = Gui(u'stdout')
            root.Show(True)
            self.SetTopWindow(root)
            return True
     
    if __name__ == '__main__':
        app = Ihm()
        app.MainLoop()
    Comme ça, ce sera plus propre.

  9. #9
    Membre confirmé
    Inscrit en
    Novembre 2007
    Messages
    66
    Détails du profil
    Informations forums :
    Inscription : Novembre 2007
    Messages : 66
    Par défaut
    La commande ping n'est qu'un exemple.
    Je pense plutôt m'en servir avec rsync...

    Mais quand ça défile trop vite ça ne marche plus !
    J'essaye de trouve quelque chose d'autre.

  10. #10
    Expert confirmé

    Homme Profil pro
    Inscrit en
    Octobre 2008
    Messages
    4 307
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Octobre 2008
    Messages : 4 307
    Par défaut
    Qu'est ce qui défile ?

    C'est mon dernier code que tu as essayé ?

    Je suis sous GNU/Linux avec python 2.6 et tout fonctionne parfaitement.

  11. #11
    Membre confirmé
    Inscrit en
    Novembre 2007
    Messages
    66
    Détails du profil
    Informations forums :
    Inscription : Novembre 2007
    Messages : 66
    Par défaut
    Je suis également sous linux et python 2.6.6.
    J'essaye de faire avec ['tree', '/usr/'] en argument...
    Et là rien ne s'affiche et ça bloque.
    Je pense que ça va trop vite.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [Débutant] Récupérer les coordonnées d'un ensemble de pixels dans une matrice
    Par reda24 dans le forum Images
    Réponses: 5
    Dernier message: 01/06/2007, 18h06
  2. récupérer le nom du serveur et l'afficher dans une jsp
    Par barouz dans le forum Servlets/JSP
    Réponses: 21
    Dernier message: 19/04/2007, 15h32
  3. Recherche croisé dans une base de donnée
    Par elephant13 dans le forum C#
    Réponses: 1
    Dernier message: 24/03/2007, 15h26
  4. Réponses: 1
    Dernier message: 31/07/2006, 13h54
  5. Réponses: 1
    Dernier message: 05/05/2006, 14h37

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo