Python: Plugging wx.py.shell.Shell into a separate

2019-04-15 02:30发布

问题:

I would like to create a shell which will control a separate process that I created with the multiprocessing module. Possible? How?

EDIT:

I have already achieved a way to send commands to the secondary process: I created a code.InteractiveConsole in that process, and attached it to an input queue and an output queue, so I can command the console from my main process. But I want it in a shell, probably a wx.py.shell.Shell, so a user of the program could use it.

回答1:

  1. First create the shell
  2. Decouple the shell from your app by making its locals empty
  3. Create your code string
  4. Compile the code string and get a code object
  5. Execute the code object in the shell
    from wx.py.shell import Shell

    frm = wx.Frame(None)
    sh = Shell(frm)
    frm.Show()    
    sh.interp.locals = {}
    codeStr = """
    from multiprocessing import Process, Queue

    def f(q):
        q.put([42, None, 'hello'])

    q = Queue()   
    p = Process(target=f, args=(q,))
    p.start()
    print q.get()    # prints "[42, None, 'hello']"
    p.join()
    """

    code = compile(codeStr, '', 'exec')
    sh.interp.runcode(code)

Note: The codeStr I stole from the first poster may not work here due to some pickling issues. But the point is you can execute your own codeStr remotely in a shell.



回答2:

You can create a Queue which you pass to the separate process. From the Python Docs:

from multiprocessing import Process, Queue

def f(q):
    q.put([42, None, 'hello'])

if __name__ == '__main__':
    q = Queue()
    p = Process(target=f, args=(q,))
    p.start()
    print q.get()    # prints "[42, None, 'hello']"
    p.join()

EXAMPLE: In the wx.py.shell.Shell Docs the constructur parameters are given as

__init__(self, parent, id, pos, size, style, introText, locals, 
         InterpClass, startupScript, execStartupScript, *args, **kwds) 

I have not tried it, but locals might be a dictionary of local variables, which you can pass to the shell. So, I would try the following:

def f(cmd_queue):
    shell = wx.py.shell.Shell(parent, id, pos, size, style, introText, locals(),
                              ...)

q = Queue()
p = Process(target=f, args=(q,))
p.start()

Inside the shell, you should then be able to put your commands into cmd_queue which have then to be read in the parent process to be executed.