Achim
Achim

Reputation: 15722

Distuils: Create script which does not "block" console when starting wx application

In my setup.py I have defined an entry point like this:

entry_points={
      'console_scripts' : [
            'cofo = cofo:gui_main'
      ]
},

Calling python setup.py develop generates the cofo script as expected. But gui_main starts a wxWindows application and I would like to "free" the console afterwards. How can I do that? If I use gui_scripts instead of console_scripts it does not make a difference.

Update:

With "free" the console, I mean that I would like to start the script from the command prompt (i.e. passing command line arguments to it), but would like to have the command prompt available after the gui has started. Something like this:

Last login: Mon Oct  8 15:34:28 on ttys002
localhost:~ domma$ cofo some arguments
... gui starts and after that ...
localhost:~ domma$ 

At the moment I don't get a waiting prompt, because the script is running and "blocking" the command line. My primary plattform is OS X, but I would be interested in a general solution.

Upvotes: 1

Views: 332

Answers (3)

gpoo
gpoo

Reputation: 8638

This happens because the shell is waiting for the process to finish. It seems you are looking for something similar to a daemon. To do that, you can use os.fork() to create a copy of the process and then terminate the main process (parent) with sys.exit().

if os.fork():
    # Finish the parent process    
    sys.exit()

# Your program starts here (child process)

Notice that this code has nothing to do with distutils. It is your program which is going to behave as a daemon.

Upvotes: 0

Gary van der Merwe
Gary van der Merwe

Reputation: 9563

With linux/unix (including Mac OS X) shells, you can run a command, and tell it to go to the background by suffixing it with "&". eg:

$ cofo some arguments &

Here is a page with some extra info on this: http://www.bsdguides.org/guides/netbsd/beginners/job_control/print

I would recommend just manaully using that/educating your users to use that (if they are already using the a cli, then that is not alot extra to ask.) If you really want your command to go the the background by default, you can wrap your script with a small bash script that uses the above mentioned method.

Upvotes: 2

Austin Phillips
Austin Phillips

Reputation: 15776

The following minimal example works for me using Windows 7 32 bit, Python 2.7.1, wx 2.8.12.2 (msw-unicode). When python setup.py develop is invoked, both cofo.exe and cofogui.exe are generated for the console and GUI scripts respectively.

When cofogui.exe is executed, no console window appears (Is this what you mean by "free" console?)

This example is using the setuptools enhancements to distutils.

setup.py:

#!/usr/bin/env python

from setuptools import setup

setup(name='cofo',
      packages=['cofo'],
      entry_points={
          'console_scripts' : [
              'cofo = cofo:gui_main'
              ],
          'gui_scripts' : [
              'cofogui = cofo:gui_main'
              ]
          }
      )

and

cofo/__init__.py:

#!/usr/bin/env python

import wx

def gui_main():
    app = wx.App(False)  # Create a new app, don't redirect stdout/stderr to a window.
    frame = wx.Frame(None, wx.ID_ANY, "Hello World") # A Frame is a top-level window.
    frame.Show(True)     # Show the frame.
    app.MainLoop()

Update: Windows and Unix based platforms operate differently when starting processes. On Unix systems, if the application is to remain running in the background the usual process is to use the os.fork() system call. As described in another answer, this can be done outside of your application by writing a wrapper script that does the backgrounding for you.

If this must be a general solution entirely in Python, then something like the following should do what you want:

cofo/__init__.py:

#!/usr/bin/env python

import os
import wx

def main_app():
    app = wx.App(False)  # Create a new app, don't redirect stdout/stderr to a window.
    frame = wx.Frame(None, wx.ID_ANY, "Hello World") # A Frame is a top-level window.
    frame.Show(True)     # Show the frame.
    app.MainLoop()

def gui_main():
    """Start GUI application.

    When running on Unix based platform, fork and detach so that terminal from
    which app may have been started becomes free for use.
    """
    if not hasattr(os, 'fork'):
        main_app()
    else:
        if os.fork() == 0:
            main_app()

Upvotes: 0

Related Questions