1

The architecture of the program consists of a PySide GUI executable build with Py2exe. Furthermore it has a second python console application build with Py2exe.

The GUI-App starts the console application using a named Pipe to be able to send CTRL_C and capture stdout/stderr. This is done using the pywin32 module.

Inside the console application several other Windows applications are executed in blocking mode using the subprocess module. Now the console application got extended by some code to execute another program in nonblocking mode.

If the GUI application and the Console application are executed (Before being build to a Py2exe App) everything works as expected and wanted. If the applications are build with Py2exe the external Windows application freezes and a windows error pops up. (application stopped working)

If the execution code of the external Windows app is isolated and a py2exe executable build, everything works.

So the problem must be py2exe and calling the console app from a GUI app.

I hope someone can point me in the right direction.

I got asked for a minimal example. The problem is that the architecture does not really allow a minimal working example. I tried my best and i hope the given Example draws a clearer image of the problem. As explained through testing the problem could be reduced to py2exe. As soon as the GUI app is "compiled" to start of a nonblocking application inside the console app works but the new application causes a windows error.

Minimal Example:

Console App console.py:

import logging
import subprocess
from time import sleep

def exec_program_nonblocking(args, cwd=None):
    if cwd:
        logging.debug("Change working directory to: %s", cwd)

    subprocess.Popen(args,
                 cwd=cwd,
                 universal_newlines=True)

def main():
    args = ["program.exe", "arg1", "arg2"]
    exec_program_nonblocking(args)
    while (True):
        print "do something \n"
        sleep(5)

if __name__ == '__main__':      
    main()

setup.py for console App:

from distutils.core import setup
import py2exe

setup(console=['console.py'])

PySide GUI application gui_app.py:

from PySide.QtGui import QApplication

def start_console_app():
    pass
    # complex implementation of openening named pipe,
    # handling callbacks, allowing to send CTRL_C to new process etc.
    # Minimal example is not possible...

app = QtGui.QApplication([])

button = QtGui.QPushButton('Start Console App')
button.clicked.connect(start_console_app)
button.show()

app.exec_()

setup.py for GUI Application:

from distutils.core import setup
import py2exe

setup(
    options = {
        'py2exe' : {
            'packages' : 'encodings',
            'unbuffered' : True
            #dll_excludes....
        }
    },
    zipfile = None,

    windows = ['gui_app.py']
)
Ben
  • 783
  • 7
  • 13
  • Please consider adding an [MCVE]. I doubt anyone will have any suggestions unless you provide some code that demonstrates the problem (also include details on how you use py2exe). – three_pineapples Sep 16 '15 at 08:38

1 Answers1

0

For me a solution posted here worked for me. Somehow py2exe messed with the handles passed from the father process, the GUI app, to the child-child process. It does not even happen with all executables that are subprocesses from the console application.

The subprocess module offers a parameter close_fds to prevent the childprocess from inherating the handles from the father process. This was not working for my application. Still, it must be related to py2exe.

giving the DETACHED_PROCESS flag to the parameter creationflags a new console is opened and the process successfully started!

The only drawback is, that stdout/stderr cannot be captured, as far as i know.

working example:

import subprocess

DETACHED_PROCESS = 0x00000008

subprocess.Popen(args,
                 cwd=cwd,
                 creationflags=DETACHED_PROCESS)
Community
  • 1
  • 1
Ben
  • 783
  • 7
  • 13