Re: [python-brasil] Subprocess Popen Linux

51 views
Skip to first unread message

Marcelo Valle

unread,
May 11, 2024, 9:06:51 AMMay 11
to python...@googlegroups.com
Eu não vou nem perguntar por que você está tentando fazer isso... Mas toca um sino na minha cabeça alarmando que isso poderia ser uma situação em que provavelmente é possível resolver o problema de uma forma mais simples. Posso estar errado. 

Aliás, verifique a funcao check_output do módulo subprocess - normalmente é mais simples que chamar POpen na mão. Chamar na mao eh só quando você está fazendo algo bem avançado mesmo, na minha opiniao...

Agora, tudo isso dito, se funciona no windows e não funciona no linux (coisa rara isso hein! rs), eu chuto que seja porque o Linux tem uma gestão melhor de sistema de arquivos com mais buffer. Quando o programa filho escrever algo para um descritor de arquivo, que pode ser um arquivo no disco ou a saída padrão do programa, nem sempre isso é escrito imediatamente. Por questões de desempenho, primeiro o dado é escrito para a memória e de tempos em tempos a memória é enviada para o destino final. Isso é chamado de flush. Mais detalhes aqui e aqui.

  • Se o programa filho for um script python que você controla, você pode fazer um flush manualmente executando . 
  • Se você não tiver controle sobre o programa filho, você pode pedir para o sistema operacional fazer um flush de IO de tudo, tem um comando no linux que faz isso, o sync.
Eu não tenho certeza se é esse mesmo o motivo de não funcionar no Linux, mas eu diria que é o mais provável.

Abracos,
Marcelo.


On Sat, 11 May 2024 at 12:40, Valmadson Santos <valm...@gmail.com> wrote:
Olá bom dia a todos. Gostaria de saber se alguém já se deparou com a seguinte situação, voce tem um programa pai que chama um programa filho, quando voce clica no botão do programa filho e neste botão tem um print("Ola"), gostaria que esse print fosse capturado pelo programa pai.

Bem eu consegui fazer com que esse programa funcione, porém ele só funciona no windows, já no linux ele funciona em parte, eu preciso sair do programa filho para essa informação ser mostrada.

alguem saberia dizer se está faltando algum argumento a ser informado para que no linux não fique guardando no buffer  ?

segue o função chamada pelo programa pai :

    def executar_script(self, script):
        output = None
        try:

            with tempfile.NamedTemporaryFile(mode='w', delete=False) as temp_script:
                temp_script.write(script)
                self.temp_file = temp_script_path = temp_script.name

            self.proc = subprocess.Popen([sys.executable, temp_script_path],
                                         stdout=subprocess.PIPE, universal_newlines=True,
                                         shell=False, bufsize=-1, close_fds=True)
            os.set_blocking(self.proc.stdout.fileno(), False)


        except subprocess.CalledProcessError as e:
            output = f"Erro de compilação:\n{e.output}"
            output += f"\n\nTraceback:\n{traceback.format_exc()}"
            print(output)

        Clock.schedule_interval(self.update_output, .25)

    def update_output(self, dt):
        msg = self.proc.stdout.readline()  # communicate blocks..
        self.output_text.text += msg

--
--
------------------------------------
Grupo Python-Brasil
https://wiki.python.org.br/AntesDePerguntar
 
<*> Para visitar o site do grupo na web, acesse:
http://groups.google.com/group/python-brasil
 
<*> Para sair deste grupo, envie um e-mail para:
python-brasi...@googlegroups.com
---
Você recebeu essa mensagem porque está inscrito no grupo "Python Brasil" dos Grupos do Google.
Para cancelar inscrição nesse grupo e parar de receber e-mails dele, envie um e-mail para python-brasi...@googlegroups.com.
Para acessar essa discussão na Web, acesse https://groups.google.com/d/msgid/python-brasil/77318f39-4461-4b34-b0ac-53642c6a0619n%40googlegroups.com.

Valmadson Santos

unread,
May 13, 2024, 11:20:49 AMMay 13
to Python Brasil
Olá Marcelo, obrigado pelo retorno.

bem eu fiz com o check_output, porém o programa filho travou:

    self.output = subprocess.check_output([sys.executable, temp_script_path], stderr=subprocess.STDOUT,  universal_newlines=True)
   
já forçando o flush, fiz assim no programa filho :

    def on_stop(self):
        print('Goodbye!')
        sys.stdout.flush()

e nada aconteceu, somente quando fecho a aplicação.

estou utilizando o framework kivy, não sei se ele tem alguma interferencia neste sentido. Segue abaixo o programa na integra caso alguém queira testar.


from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.uix.textinput import TextInput
from kivy.config import Config
from kivy.clock import Clock
import subprocess
import traceback
import tempfile
import os
import sys

Config.set('graphics', 'width', '500')
Config.set('graphics', 'height', '300')

my_script = """
from kivy.app import App
from kivy.config import Config
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.lang import Builder
import sys

Config.set('graphics', 'width', '300')
Config.set('graphics', 'height', '200')

class Window(App):
n = 0
def build(self):
layout = BoxLayout(orientation='vertical')
self.output_label = Button(text='click-me and leave')
self.output_label.bind(on_press=self.sayhello)
layout.add_widget(self.output_label)
return layout

def sayhello(self, arg):
self.n += 1
print(f'{self.n} Hello!')
def on_stop(self):
print('Goodbye!')
sys.stdout.flush()

Window().run()
"""


class NewWindow(App):
def build(self):
layout = BoxLayout(orientation='vertical')

self.input_text = TextInput(text=my_script)
layout.add_widget(self.input_text)

compile_button = Button(text='Execute script')
compile_button.bind(on_press=self.click)
layout.add_widget(compile_button)

self.output_text = TextInput(readonly=True, multiline=True)
layout.add_widget(self.output_text)

return layout

def click(self, arg):
# thread = Thread(target=self.executar_script, args=(self.input_text.text,))
# thread.start()
self.executar_script(self.input_text.text)

def executar_script(self, script):
output = None
try:

with tempfile.NamedTemporaryFile(mode='w', delete=False) as temp_script:
temp_script.write(script)
self.temp_file = temp_script_path = temp_script.name
if tempfile.gettempdir() in temp_script_path:
print("Arquivo temporário criado com sucesso:", temp_script_path)
else:
print("Erro: O arquivo não é um arquivo temporário.")

#self.output = subprocess.check_output([sys.executable, temp_script_path], stderr=subprocess.STDOUT, universal_newlines=True)

self.proc = subprocess.Popen([sys.executable, temp_script_path],
stdout=subprocess.PIPE, universal_newlines=True,
shell=False, bufsize=-1, close_fds=True)
os.set_blocking(self.proc.stdout.fileno(), False)

# self.verificar_arquivo_temporario(temp_script_path)
#print('post popen', output)

except subprocess.CalledProcessError as e:
output = f"Erro de compilação:\n{e.output}"
output += f"\n\nTraceback:\n{traceback.format_exc()}"
print(output)
# finally: # this deletes the file prior to the subprocess reading the file.
# os.unlink(temp_script_path)

Clock.schedule_interval(self.update_output, .25)

def update_output(self, dt):
msg = self.proc.stdout.readline() # communicate blocks..
#msg = self.output.readline() # communicate blocks..
self.output_text.text += msg

def on_stop(self):
os.unlink(self.temp_file)

NewWindow().run()

Marcelo Valle

unread,
May 13, 2024, 6:56:34 PMMay 13
to python...@googlegroups.com
Valmadson,

Acho que a questão é a forma como você está lendo o output no programa pai. 

Eu não tenho como testar seu programa, nem sei o que é kivy, mas seria algo mais ou menos assim:

Abracos,
Marcelo.

Valmadson Santos

unread,
May 14, 2024, 8:39:44 AMMay 14
to Python Brasil
obrigado Marcelo, vou dar uma verificada nos exemplos.

Renato Moraes

unread,
May 14, 2024, 1:38:01 PMMay 14
to Python Brasil
Valmadson me responde uma pergunta, você está querendo criar um app gui para executar outros scripts que contém o kivy?
Se sim pense bem no final da execução de script filho colocar um sinal de término, tal como  App.get_running_app().stop()

Valmadson Santos

unread,
May 14, 2024, 2:12:27 PMMay 14
to Python Brasil
Valeu Renato é isso mesmo que estou pensando. 

Obrigado pela dica, já vou implementar !

Valmadson Santos

unread,
May 14, 2024, 5:39:06 PMMay 14
to Python Brasil
consegui interceptar as mensagens desta forma :

self.popen = Popen([sys.executable, '-u', temp_script_path], bufsize=1, stdout=PIPE, stderr=subprocess.STDOUT, text=True)
with self.popen as sub:
for line in sub.stdout:
self.update_output(line)

agradeço a todos pela atenção !
Reply all
Reply to author
Forward
0 new messages