Welcome, guest | Sign In | My Account | Store | Cart

Make a wxPython application also acting as a XML-RPC server, listening to a dedicated port. For example a GUI logging application, where logging messages come from other applications via xml-rpc calls.

Python, 78 lines
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
# -*- coding: iso-8859-1 -*-

import  wx
from twisted.internet import wxreactor
wxreactor.install()
from twisted.internet import reactor
from twisted.web import xmlrpc, server
    

#---------------------------------------------------------------------------

class MyFrame(wx.Frame):
    def __init__(
            self, parent, ID, title, pos=wx.DefaultPosition,
            size=wx.DefaultSize, style=wx.DEFAULT_FRAME_STYLE
            ):

        wx.Frame.__init__(self, parent, ID, title, pos, size, style)
        
        panel = wx.Panel(self, -1)

        button = wx.Button(panel, 1003, "Close Me")
        button.SetPosition((15, 15))
        self.Bind(wx.EVT_BUTTON, self.OnCloseMe, button)
        self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)

    def OnCloseMe(self, event):
        self.Close(True)
        reactor.stop()

    def OnCloseWindow(self, event):
        self.Destroy()
        reactor.stop()

#---------------------------------------------------------------------------

class MyXMLRPCApp(wx.App, xmlrpc.XMLRPC):
    # Make a mixin of both
    
    # the wx related startup code, building the gui
    def OnInit(self):
        self.frame = MyFrame(None, -1, 'Hallo')
        self.frame.Show(True)
        self.SetTopWindow(self.frame)
        return True

    # some XML-RPC function calls for twisted server
    def xmlrpc_stop(self):
        """Closes the wx application."""
        self.frame.Close() # Sending closing event
        return 'Shutdown initiated'

    def xmlrpc_title(self, x):
        """Return all passed args."""
        self.frame.SetTitle(x)
        return x.upper()

    def xmlrpc_add(self, a, b):
        """Return sum of arguments."""
        return a + b
    


if __name__ == '__main__':

    # Initiliaze MyApp
    app = MyXMLRPCApp(False) # False -> printing stdout/stderr to shell, 
                             # not in an additional wx window
    
    # Make wx application twisted aware
    # Must have to start "wxreactor.install()" on top before
    reactor.registerWxApp(app)    

    # Make a XML-RPC Server listening to port 7080
    reactor.listenTCP(7080, server.Site(app))

    # Start both reactor parts (wx MainLoop and XML-RPC server)
    reactor.run()
    
    

Focus: Make a wxPython application also acting as a XML-RPC server, listening to a dedicated port.

Problem: A wx application has a mainloop, so has the xml-rpc server. Various approaches to join these loops are: - blocking - ugly / hackish - complex

Solution: Twisted wxreactor to support wxPython (/TwistedDocs/examples/wxdemo.py) Twisted xml-rpc server (/TwistedDocs/howto/xmlrpc.xhtml)

Joining them compact into this demo.

Testing: Starting module from shell. Opening other shell with python interpreter:

>>> from xmlrpclib import *
>>> s = ServerProxy('http://localhost:7080') # Get access to xmlrpc server

>>> s.title('Hallo xmlrpc app') # this call changes the title of the wx application
'HALLO XMLRPC APP'

>>> s.add(4,5) # a non gui related call
9

>>> s.stop() # killing the wx application
'Shutdown initiated'

Environment: Python 2.3.4 wxPython 2.5.1.5 twisted 1.3.0

Tested on WIN XP

1 comment

Ian Jones 15 years, 4 months ago  # | flag

On WinXP with wxPython 2.8.9.1 and Twisted 8.1 I needed to change the following for it to work:

... class MyXMLRPCApp(wx.App, xmlrpc.XMLRPC): # Make a mixin of both allowNone = True ...