Search code examples
pythonpy2exedistutils

Is it possible to have a python shell in a py2exe build?


I distribute a software package for windows via distutils and py2exe. For development purposes, I'd like to be able to have access to a python console inside the py2exe build. I see there is a python27.dll file in the py2exe build, so I hope I can leverage that to launch a python terminal.

Is it possible to take an existing, or modify distutils/py2exe to get end user access to a Python shell in the py2exe environment?


Solution

  • There's a really bare-bones way to accomplish this as documented by Matt Anderson from the pymntos google group. I've seen some variations on it, but this one came up first when I googled. :p

    The juice is in the stdlib code module, leveraging code.InteractiveInterpeter. The only thing you'd have to do is add this in as a thread as the application starts. Then, when the app starts you can telnet 'localhost 7777' and you should drop into a Python interpreter.

    The problem with doing it as a thread though - you can't very easily twiddle variables / data in the main thread without doing some sort of queue and passing things around.

    You could alternatively have an async socket - that way you could twiddle stuff as a main-thread participant. Thats inherently dangerous for a host of reasons. But, we're talking bare metal.

    If you use the Twisted library, you could use Twisted Conch, which allows you to create an SSH or Telnet server that can talk to the rest of your app. However, this might be a problem since you're using the event loop from the UI to process events - you can't have two event loops. If you're using Qt, there is a Twisted Qt Reactor event loop. If it's windows or something else.. I have no idea. But, this should at least give you a few things to consider.

    Original link is: https://groups.google.com/forum/?fromgroups#!topic/pymntos/-Mjviu7R2bs

    import socket
    import code
    import sys
    
    class MyConsole(code.InteractiveConsole):
        def __init__(self, rfile, wfile, locals=None):
            self.rfile = rfile
            self.wfile = wfile
            code.InteractiveConsole.__init__(
                self, locals=locals, filename='<MyConsole>')
    
        def raw_input(self, prompt=''):
            self.wfile.write(prompt)
            return self.rfile.readline().rstrip()
    
        def write(self, data):
            self.wfile.write(data)
    
    
    netloc = ('', 7777)
    servsock = socket.socket()
    servsock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
    servsock.bind(netloc)
    servsock.listen(5)
    print 'listening'
    sock, _ = servsock.accept()
    print 'accepted'
    
    rfile = sock.makefile('r', 0)
    sys.stdout = wfile = sock.makefile('w', 0)
    
    console = MyConsole(rfile, wfile)
    console.interact()