Bienvenue sur IndexError.

Ici vous pouvez poser des questions sur Python et le Framework Django.

Mais aussi sur les technos front comme React, Angular, Typescript et Javascript en général.

Consultez la FAQ pour améliorer vos chances d'avoir des réponses à vos questions.

Subprocess et Python en mode "no-console"

+3 votes

J'ai cette classe :

import subprocess, sys

class Olelink(object) :
    def __init__(self) :
        self.exe = "core.exe"
        self.v = View()
        self.v.root.resizable(0,0)

    def getPort(self) :
        """Renvoi le port écouté sur localhost du programme exe"""

        encoding = sys.stdout.encoding #encodage de la console

        #on trouve le pid du programme
        pid = subprocess.check_output("tasklist /fo csv", shell=True).decode(encoding).split("\r\n")

        #mise en forme
        pid = [x.replace('"','').split(",")[0:2] for x in pid]

        #on vérifie que le programme est bien lancé
        try :
            pid = [x for x in pid if x[0] == self.exe][0][1]
        except :
            print("Coala n'est pas lancé")
            sys.exit()

        #on récupère le port
        net = subprocess.Popen("netstat -ano", stdout=subprocess.PIPE, shell=True)
        find = subprocess.check_output("findstr "+str(pid), stdin=net.stdout, shell=True)
        net.stdout.close()
        net = find.decode(encoding).split("\r\n")

        #mise en forme
        ports = []
        for x in net :
            if x != "" :
                z = x.strip().split(" ")
                z = [y for y in z if y != ""]
                ports.append(z)

        #on récupère l'adresse du serveur OLE
        port = False
        for x in ports :
            if "127.0.0.1" in x[1] :
                port = x[1]

        #on vérifie que le serveur OLE est bien lancé
        if port :
            print("Serveur Ole détecté")
            return port
        else :
            print("Ole non initialisé, attendez et relancez")
            sys.exit()

    def genIni(self) :
        """Génère le fichier ini nécessaire au ClientOle"""

        with open("Parametres_AssistantOLE.ini", "w") as f :
            ini = "[PARAMETERS]"+self.getPort()
            f.write(ini)

if __name__ == "__main__" :
    app = Olelink()
    app.genIni()
    app.v.root.mainloop()

Le but est de récupérer le port écouté par un programme, le stocker dans un fichier texte et ouvrir une interface graphique.
Lorsque je double-clique dessus, il fonctionne sans problème.
En revanche, lorsque je change l'extension de .py à .pyw, pour ne pas avoir de console qui s'affiche, il ne marche plus.
L'interface graphique n’apparait pas, et le fichier texte est créé mais il reste vide.

demandé 10-Jul-2015 par Zara (200 points)

1 Réponse

+3 votes
 
Meilleure réponse

Quand tu lances ton programme avec pythonw (enfin en mode sans console quoi), sys.stdout.encoding est à None (bah ouais, ya pas de console donc théoriquement il n'y a pas de stdout).

Du coup string.decode souleve une TypeError, attendant une string.

répondu 11-Jul-2015 par Arza (726 points)
sélectionné 14-Jul-2015 par Zara

Merci beaucoup cher anagramme ! Je n'avais pas du tout pensé à ça.

D'après ce ticket, il faudrait paramétrer l'encoding non pas sur celui du terminal, mais sur celui du "system code page". Or je n'ai pas trouvé comment faire ça.

Deuxième solution que mes recherches ont soulevée, modifier l'encoding de sys.stdout, comme indiqué ici, avec la ligne :

sys.stdout = codecs.getwriter("utf-8")(sys.stdout.detach())

Enfin dernière hypothèse, mon programme n'est destiné qu'aux Windows, l'encoding est-il constant sur tous les systèmes ? Si oui, je pourrai indiquer l'encodage en dur.

Ce thread propose plusieurs réponses:

from ctypes import cdll
import locale
print('cp' + str(cdll.kernel32.GetACP()))
print(locale.getpreferredencoding())

Pour répondre à ton hypothèse, je pense que sur Windows l'encoding change en fonction du couple version/pays, mais je n'ai pas assez de connaissances sur Windows pour pouvoir l'affirmer à 100%.

Désolé de répondre aussi tardivement, je ne pouvais pas tester avant.
Effectivement, la solution "cdll" et la solution "locale" fonctionnent toutes deux en mode "no-console".
Le souci que je rencontre, c'est que ces deux fonctions ne renvoient pas le même encodage que sys.stdout.encoding lorsque je lance le programme dans la console :

print(sys.stdout.encoding)
#cp850
print(locale.getpreferredencoding())
#cp1252

En revanche, lorsque le programme est exécuté dans Idle, ces deux lignes renvoient toutes deux "cp1252".

...