Differences between revisions 2 and 6 (spanning 4 versions)
Revision 2 as of 2005-07-03 21:38:59
Size: 5351
Editor: aaron
Comment: make it run from CGI?
Revision 6 as of 2009-12-03 23:20:31
Size: 5220
Editor: vpn-8061f549
Comment:
Deletions are marked like this. Additions are marked like this.
Line 1: Line 1:
This is an "automatic DocXmlRpcServer." This is an "automatic DocXmlRpcServer." There is also a CGI variant: AutoXmlRpcCgi.
Line 3: Line 3:
[[TableOfContents()]] <<TableOfContents>>
Line 15: Line 15:
How can you share that on [http://www.irchelp.org/ IRC?] How can you share that on [[http://www.irchelp.org/|IRC?]]
Line 49: Line 49:
 * What if you can't run a server? Use AutoXmlRpcCgi!
Line 52: Line 53:
 * If you define a function "uli" ({{{def uli(msg):}}}), you can call it in IRC with [http://onebigsoup.wiki.taoriver.net/moin.cgi/UliBot UliBot!]  * If you define a function "uli" ({{{def uli(msg):}}}), you can call it in IRC with [[http://onebigsoup.wiki.taoriver.net/moin.cgi/UliBot|UliBot!]]
Line 76: Line 77:
import sets
Line 91: Line 91:
    modules = sets.Set()     modules = set()
Line 150: Line 150:
            if func.__name__.startswith("_"):
                continue
Line 174: Line 176:
-- LionKimbro [[DateTime(2005-04-17T05:51:41Z)]]

And another one:

Can you make a CGI version? Something that does just what this does, but as a CGI, rather than continuously running server? [http://effbot.org/zone/xmlrpc-cgi.htm This page on using XML-RPC with CGI might help.]

-- LionKimbro [[DateTime(2005-07-03T21:38:55Z)]]
-- LionKimbro <<DateTime(2005-04-17T05:51:41Z)>>

This is an "automatic DocXmlRpcServer." There is also a CGI variant: AutoXmlRpcCgi.

Tutorial

Suppose you have a Python module:

   1 def spam():
   2     return "spam"

How can you share that on IRC?

Mark it like this:

   1 XMLRPC_namespace = "eggs"
   2 
   3 def spam():
   4     return "spam"

Now, just run the AutoXmlRpcServer from that directory, and you're done!

$ ./xrserver.py
Sat Apr 16 21:29:24 2005 Application Starting.

You're XML-RPC server's up and running, port 8000.

Your friends can now call your function!

   1 import xmlrpclib
   2 
   3 server = xmlrpclib.ServerProxy("http://example.com:8000/")
   4 print server.eggs.spam()

There it is!

Notes

  • What if you can't run a server? Use AutoXmlRpcCgi!

  • You can change the host and portname. Run "./xrserver --help" for options.
  • If you set XMLRPC_namespace to None, then namespaces aren't used.
  • This code demonstrates ModulesAsPlugins, DocXmlRpcServer, OptParse, and (hopefully) PythonStyle.

  • If you define a function "uli" (def uli(msg):), you can call it in IRC with UliBot!

Code: xrserver.py

   1 #!/usr/bin/env python
   2 """Serve specially marked modules by XML-RPC.
   3 
   4   -Hhostname   host name, default ""
   5   -Pportnum    port number, default 8000
   6 
   7 This script starts an XML-RPC server, and publishes auto-detected
   8 modules from the working directory.
   9 
  10 Functions within Modules that define the name "XMLRPC_namespace" are
  11 published. Function names that begin with an underscore (ex: _eggs) are
  12 not published. Functions are published within the XML-RPC namespace
  13 designated by the XMLRPC_namespace value, or the base namespace if the
  14 value is None.
  15 """
  16 
  17 import time
  18 import os
  19 import imp
  20 import types
  21 
  22 import optparse
  23 import DocXMLRPCServer
  24 
  25 
  26 def find_modules(path="."):
  27     """Return names of modules in a directory.
  28 
  29     Returns module names in a list. Filenames that end in ".py" or
  30     ".pyc" are considered to be modules. The extension is not included
  31     in the returned list.
  32     """
  33     modules = set()
  34     for filename in os.listdir(path):
  35         module = None
  36         if filename.endswith(".py"):
  37             module = filename[:-3]
  38         elif filename.endswith(".pyc"):
  39             module = filename[:-4]
  40         if module is not None:
  41             modules.add(module)
  42     return list(modules)
  43 
  44 
  45 def load_module(name, path=["."]):
  46     """Return a named module found in a given path."""
  47     (file, pathname, description) = imp.find_module(name, path)
  48     return imp.load_module(name, file, pathname, description)
  49 
  50 
  51 def find_xmlrpc_modules():
  52     """Find modules that define XMLRPC_namespace.
  53 
  54     Loads all modules in the current working directory. Returns a list
  55     of modules, the modules that define XMLRPC_namespace.
  56     """
  57     modules = [load_module(m) for m in find_modules()]
  58     xmlrpc_modules = []
  59     for m in modules:
  60         if m.__dict__.has_key("XMLRPC_namespace"):
  61             xmlrpc_modules.append(m)
  62     return xmlrpc_modules
  63 
  64 
  65 def functions_in_module(module):
  66     """Find all functions in a module."""
  67     functions = []
  68     for obj in module.__dict__.values():
  69         if isinstance(obj, types.FunctionType):
  70             functions.append(obj)
  71     return functions
  72 
  73 
  74 if __name__ == "__main__":
  75     parser = optparse.OptionParser(__doc__)
  76     parser.add_option("-H", "--host", dest="hostname",
  77                       default="127.0.0.1", type="string",
  78                       help="specify hostname to run on")
  79     parser.add_option("-p", "--port", dest="portnum", default=8000,
  80                       type="int", help="port number to run on")
  81 
  82     (options, args) = parser.parse_args()
  83     if len(args) != 0:
  84         parser.error("incorrect number of arguments")
  85 
  86     ServerClass = DocXMLRPCServer.DocXMLRPCServer
  87     server = ServerClass((options.hostname, options.portnum),
  88                          logRequests=0)
  89 
  90     for module in find_xmlrpc_modules():
  91         for func in functions_in_module(module):
  92             if func.__name__.startswith("_"):
  93                 continue
  94             full_name = func.__name__
  95             if module.XMLRPC_namespace is not None:
  96                 full_name = "%s.%s" % (module.XMLRPC_namespace,
  97                                        full_name)
  98             server.register_function(func, full_name)
  99 
 100     server.set_server_title("xrserver")
 101     server.register_introspection_functions()
 102 
 103     print time.asctime(), 'Application Starting.'
 104     server.serve_forever()
 105     print time.asctime(), 'Application Finishing.'

Discussion

This could be improved. Some ideas:

  • Make it so you can specify modules (and possibly namespaces for them) with command line options. (hint: OptParse.)

  • What if there's an exception while loading a module? What then?
  • Respond gracefully to CTRL-C.
  • Log modules successfully loaded.
    • If you're either brave or insane, make use of the LoggingModule.

-- LionKimbro 2005-04-17 05:51:41

AutoXmlRpcServer (last edited 2009-12-03 23:20:31 by vpn-8061f549)

Unable to edit the page? See the FrontPage for instructions.