Python xmlrpc servers?

T

ted holden

I have a project for which being able to write xmlrpc server code in python
would be vastly preferable to the second choice solution for a number of
reasons. Unfortunately, pretty much everything I see on the net in the way
of documentation appears either insufficient or outdated.

The example given in the Python documentation for SimpleXMLRPCServer is
more or less incomprehensible. That example is as follows:

class MyFuncs:
def div(self, x, y) : return div(x,y)

handler = CGIXMLRPCRequestHandler()
handler.register_function(pow)
handler.register_function(lambda x,y: x+y, 'add')
handler.register_introspection_functions()
handler.register_instance(MyFuncs())
handler.handle_request()

I don't see where the "div(x,y)" which is returned in the class function
definition comes from. I don't see any relationship between the class
MyFuncs and the rest of the program. I don't see where the returned
function "pow" comes from or what its relevance is. I don't see what
"lambda" is or how a lambda function is supposed to be construed as adding
two numbers together. I don't see how this server is supposed to be used.

I also find an example written by Dave Warner:

http://www.onlamp.com/pub/a/python/2001/01/17/xmlrpcserver.html

which is about four years old and dated. In particular, the include file
xmlrpcserver which he imports no longer exists.

And then, I find one example in an IBM reference which actually does work as
stated on a single computer:

http://www-106.ibm.com/developerworks/webservices/library/ws-pyth10.html

The test client provided looks like:

mport xmlrpclib

server = xmlrpclib.ServerProxy("http://localhost:8888")
month = server.getMonth(2002, 8)
print month


which actually works. Nonetheless I need this thing to work across
machines. I have a primitive network here usingVerizon DMS and a Linksys
router which sees the three computers on it as 192.168.1.100,
192.168.1.101, and 192.168.1.102 as usual.

Question is, what does it take to run the server on 102 and a client on 100?

Changing the obvious line in the client program to:

server = xmlrpclib.ServerProxy("http://192.168.1.102:8888")

doesn't work. Aside from that, I'd like to get the CGI version of the thing
which uses .py files in the CGI bin to work as well and again the only
example I see of that (in the Python documentation) is undecipherable.

I'd appreciate any suggestions or info anybody might have.
 
S

Skip Montanaro

ted> The example given in the Python documentation for
ted> SimpleXMLRPCServer is more or less incomprehensible.

Agreed, there is a doc fix needed. Try mentally adding

from math import *

to the start of the example. That will get you the pow function. It's
still incorrect though. There's no div function, either builtin or in the
math module. The MyFuncs class should be defined as in the 2.4 docs:

class MyFuncs:
def div(self, x, y) : return x // y

ted> I don't see any relationship between the class MyFuncs and the rest
ted> of the program.

In this simpleminded example, there is none. The goal of the example is to
show how the register_* methods are used. In a real-life application any
instances registered would probably store considerable parts of the
application state or be able to communicate with those objects that do.

ted> I don't see what "lambda" is or how a lambda function is supposed
ted> to be construed as adding two numbers together.

Lambda is a keyword in Python used to create and return very simple
(single-expression) functions. Lambda expressions can be used anywhere
you'd normally use a function object. See:

http://www.python.org/doc/current/ref/lambdas.html

The line containing the lambda expression:

server.register_function(lambda x,y: x+y, 'add')

could be recast as:

def add(x, y):
return x+y

server.register_function(add, 'add')

though the second arg isn't required since it matches the function's
__name__ attribute. It's required when a lambda expression is used though
because lambda expressions don't have terribly useful __name__ attributes:
... return x+y
... 'add'

ted> And then, I find one example in an IBM reference which actually
ted> does work as stated on a single computer:
...
ted> which actually works. Nonetheless I need this thing to work across
ted> machines.

The server listens to "localhost" on port 8888. To allow it to listen for
external connections change "localhost" to the name or IP address of the
server. Before you do that make sure you understand the ramifications of
exposing your XML-RPC server to a broader class of potential clients, some
of which are bound to be malicious.

Skip
 
T

ted holden

Skip Montanaro wrote:

ted> I don't see what "lambda" is or how a lambda function is supposed
ted> to be construed as adding two numbers together.

Lambda is a keyword in Python used to create and return very simple
(single-expression) functions. Lambda expressions can be used anywhere
you'd normally use a function object. See:

http://www.python.org/doc/current/ref/lambdas.html

The line containing the lambda expression:

server.register_function(lambda x,y: x+y, 'add')

could be recast as:

def add(x, y):
return x+y

server.register_function(add, 'add')

That's a whole lot easier to digest. I'd have assumed lambda was some sort
of stat function...

The server listens to "localhost" on port 8888. To allow it to listen for
external connections change "localhost" to the name or IP address of the
server. Before you do that make sure you understand the ramifications of
exposing your XML-RPC server to a broader class of potential clients, some
of which are bound to be malicious.

Skip


Many thanks, that's the part I was missing in the case of standalone
servers. The only other real question is what about the cgi servers? I'd
assume I'd take the example given:

class MyFuncs:
def div(self, x, y) : return div(x,y)

handler = CGIXMLRPCRequestHandler()
handler.register_function(pow)
handler.register_function(lambda x,y: x+y, 'add')
handler.register_introspection_functions()
handler.register_instance(MyFuncs())
handler.handle_request()

Stuff that into a file in the cgi-bin dir on the server, and then try to use
something like:


server = xmlrpclib.Server("http://192.168.1.102/testserver.py")
or
server = xmlrpclib.Server("http://192.168.1.102/cgi-bin/testserver.py")


That still hasn't worked, so far at least.
 
S

Skip Montanaro

ted> Would several web services on the same server listen on different
ted> ports (8888, 8889, 8890...) or on the same port?

Port numbers are never implicit. You need to provide a listen port each
time you start the server.

Skip
 
S

Skip Montanaro

ted> The only other real question is what about the cgi servers? I'd
ted> assume I'd take the example given:

ted> class MyFuncs:
ted> def div(self, x, y) : return div(x,y)

ted> handler = CGIXMLRPCRequestHandler()
ted> handler.register_function(pow)
ted> handler.register_function(lambda x,y: x+y, 'add')
ted> handler.register_introspection_functions()
ted> handler.register_instance(MyFuncs())
ted> handler.handle_request()

ted> Stuff that into a file in the cgi-bin dir on the server, and then
ted> try to use something like:

ted> server = xmlrpclib.Server("http://192.168.1.102/testserver.py")
ted> or
ted> server = xmlrpclib.Server("http://192.168.1.102/cgi-bin/testserver.py")

ted> That still hasn't worked, so far at least.

I've never used XML-RPC in a CGI context before. Have you looked in your
web server's error log file?

Skip
 
T

ted holden

Jaime said:
Mark Pilgrim wrote a really neat piece of python code that did XML-RPC
over CGI. It seems to have disappeared from his website, though
(http://diveintomark.org/public/webservices.txt).

If you can't dig it up, I have a working copy that I use. I'll post
it / email it if you want.

Thanks, couldn't hurt anything to post it. Again the real problem seems to
be the cnostant state of flux of open software and the attempts to have
machines and software write documentation don't really seem to help much.


Ted
 
S

Skip Montanaro

ted> Shoulda thought of that.... It's telling me that the name
ted> CGIXMLRPCRequestHandler is not found. In other words, it is trying
ted> to execute the proper file at least. I'd have that that importing
ted> SimpleXMLRPCServer would have sufficed to make the right classes
ted> available.

Sounds like you are executing

import SimpleXMLRPCServer

If so, you need to qualify the reference to the handler class like

SimpleXMLRPCServer.CGIXMLRPCRequestHandler

An import statement loads the specified module and binds a variable in the
current scope to the resulting module object. There's a builtin __import__
function that imports and returns a module object. The above import
statement is equivalent to

SimpleXMLRPCServer = __import__("SimpleXMLRPCServer")

If you want to import selected names from the module's namespace you can
execute

from SimpleXMLRPCServer import CGIXMLRPCRequestHandler

which creates a binding in the current namespace called
"CGIXMLRPCRequestHandler" associated with that class.

Skip
 
T

ted holden

Skip Montanaro wrote:

If so, you need to qualify the reference to the handler class like

SimpleXMLRPCServer.CGIXMLRPCRequestHandler

Again thanks, that works. If I weren't worried about jinxing myself I'd say
I seem to be in pretty good shape at this point...

Ted
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,982
Messages
2,570,186
Members
46,739
Latest member
Clint8040

Latest Threads

Top