Differences between revisions 5 and 6
Revision 5 as of 2009-09-15 14:16:39
Size: 235
Editor: 66-193-211-70
Comment: doors.txt;10;15
Revision 6 as of 2009-09-15 18:35:25
Size: 4233
Editor: PaulBoddie
Comment: Revert vandalism.
Deletions are marked like this. Additions are marked like this.
Line 1: Line 1:
This is a CGI version of the "automatic DocXmlRpcServer."
Line 2: Line 3:
---- /!\ '''Edit conflict - other version:''' ----
doors.txt;10;15
----
CategoryPyCon2010
<<TableOfContents>>
Line 7: Line 5:
---- /!\ '''Edit conflict - your version:''' ----
doors.txt;10;15
----
CategoryPyCon2010
== Tutorial ==
Line 12: Line 7:
---- /!\ '''End of edit conflict''' ---- Suppose you have a Python module:

{{{
#!python
def spam():
    return "spam"
}}}

How can we quickly share this functionality?

Mark it like this:
{{{
#!python
XMLRPC_namespace = "eggs"

def spam():
    return "spam"
}}}

Now, put that script, and the AutoXmlRpcCgi script, into a CGI directory. You're done!

You can use that function via XML-RPC on the CGI.

Your friends can now call your function!

{{{
#!python
import xmlrpclib

server = xmlrpclib.ServerProxy("http://example.net/xrcgi.py")
print server.eggs.spam()
}}}

There it is!

== Notes ==

 * If you set XMLRPC_namespace to None, then namespaces aren't used.
 * This code demonstrates ModulesAsPlugins, CgiScripts, DocXmlRpcServer, and (hopefully) PythonStyle.
 * 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!]]

== Code: xrcgi.py ==

{{{
#!python
#!/usr/bin/env python2.4
"""CGI between XML-RPC web requests, and specially marked modules.

This script is a gateway (CGI) between web XML-RPC requests, and
Python modules that define "XMLRPC_namespace".

Functions within Modules that define the name "XMLRPC_namespace" are
accessible by XML-RPC. Function names that begin with an underscore (ex:
_eggs) are not published. Functions are published within the XML-RPC
namespace designated by the XMLRPC_namespace value, or the base
namespace if the value is None.
"""

import time
import os
import sets
import imp
import types

import DocXMLRPCServer


def find_modules(path="."):
    """Return names of modules in a directory.

    Returns module names in a list. Filenames that end in ".py" or
    ".pyc" are considered to be modules. The extension is not included
    in the returned list.
    """
    modules = sets.Set()
    for filename in os.listdir(path):
        module = None
        if filename.endswith(".py"):
            module = filename[:-3]
        elif filename.endswith(".pyc"):
            module = filename[:-4]
        if module is not None:
            modules.add(module)
    return list(modules)


def load_module(name, path=["."]):
    """Return a named module found in a given path."""
    (file, pathname, description) = imp.find_module(name, path)
    return imp.load_module(name, file, pathname, description)


def find_xmlrpc_modules():
    """Find modules that define XMLRPC_namespace.

    Loads all modules in the current working directory. Returns a list
    of modules, the modules that define XMLRPC_namespace.
    """
    modules = [load_module(m) for m in find_modules()]
    xmlrpc_modules = []
    for m in modules:
        if m.__dict__.has_key("XMLRPC_namespace"):
            xmlrpc_modules.append(m)
    return xmlrpc_modules


def functions_in_module(module):
    """Find all functions in a module."""
    functions = []
    for obj in module.__dict__.values():
        if isinstance(obj, types.FunctionType):
            functions.append(obj)
    return functions


if __name__ == "__main__":
    handler = DocXMLRPCServer.DocCGIXMLRPCRequestHandler()

    for module in find_xmlrpc_modules():
        for func in functions_in_module(module):
            if func.__name__.startswith("_"):
                continue
            full_name = func.__name__
            if module.XMLRPC_namespace is not None:
                full_name = "%s.%s" % (module.XMLRPC_namespace,
                                       full_name)
            handler.register_function(func, full_name)

    handler.set_server_title("xrserver")
    handler.register_introspection_functions()
    handler.register_multicall_functions()
    handler.handle_request()
}}}

= Discussion =

This could be improved. Some ideas:

 * What if there's an exception while loading a module? What then?
 * Log modules successfully loaded.
    * If you're either brave or insane, make use of the LoggingModule.
 * Perhaps perform some sort of caching, to speed up invocation.

-- LionKimbro <<DateTime(2005-04-17T05:51:41Z)>>

This is a CGI version of the "automatic DocXmlRpcServer."

Tutorial

Suppose you have a Python module:

   1 def spam():
   2     return "spam"

How can we quickly share this functionality?

Mark it like this:

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

Now, put that script, and the AutoXmlRpcCgi script, into a CGI directory. You're done!

You can use that function via XML-RPC on the CGI.

Your friends can now call your function!

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

There it is!

Notes

Code: xrcgi.py

   1 #!/usr/bin/env python2.4
   2 """CGI between XML-RPC web requests, and specially marked modules.
   3 
   4 This script is a gateway (CGI) between web XML-RPC requests, and
   5 Python modules that define "XMLRPC_namespace".
   6 
   7 Functions within Modules that define the name "XMLRPC_namespace" are
   8 accessible by XML-RPC. Function names that begin with an underscore (ex:
   9 _eggs) are not published. Functions are published within the XML-RPC
  10 namespace designated by the XMLRPC_namespace value, or the base
  11 namespace if the value is None.
  12 """
  13 
  14 import time
  15 import os
  16 import sets
  17 import imp
  18 import types
  19 
  20 import DocXMLRPCServer
  21 
  22 
  23 def find_modules(path="."):
  24     """Return names of modules in a directory.
  25 
  26     Returns module names in a list. Filenames that end in ".py" or
  27     ".pyc" are considered to be modules. The extension is not included
  28     in the returned list.
  29     """
  30     modules = sets.Set()
  31     for filename in os.listdir(path):
  32         module = None
  33         if filename.endswith(".py"):
  34             module = filename[:-3]
  35         elif filename.endswith(".pyc"):
  36             module = filename[:-4]
  37         if module is not None:
  38             modules.add(module)
  39     return list(modules)
  40 
  41 
  42 def load_module(name, path=["."]):
  43     """Return a named module found in a given path."""
  44     (file, pathname, description) = imp.find_module(name, path)
  45     return imp.load_module(name, file, pathname, description)
  46 
  47 
  48 def find_xmlrpc_modules():
  49     """Find modules that define XMLRPC_namespace.
  50 
  51     Loads all modules in the current working directory. Returns a list
  52     of modules, the modules that define XMLRPC_namespace.
  53     """
  54     modules = [load_module(m) for m in find_modules()]
  55     xmlrpc_modules = []
  56     for m in modules:
  57         if m.__dict__.has_key("XMLRPC_namespace"):
  58             xmlrpc_modules.append(m)
  59     return xmlrpc_modules
  60 
  61 
  62 def functions_in_module(module):
  63     """Find all functions in a module."""
  64     functions = []
  65     for obj in module.__dict__.values():
  66         if isinstance(obj, types.FunctionType):
  67             functions.append(obj)
  68     return functions
  69 
  70 
  71 if __name__ == "__main__":
  72     handler = DocXMLRPCServer.DocCGIXMLRPCRequestHandler()
  73 
  74     for module in find_xmlrpc_modules():
  75         for func in functions_in_module(module):
  76             if func.__name__.startswith("_"):
  77                 continue
  78             full_name = func.__name__
  79             if module.XMLRPC_namespace is not None:
  80                 full_name = "%s.%s" % (module.XMLRPC_namespace,
  81                                        full_name)
  82             handler.register_function(func, full_name)
  83 
  84     handler.set_server_title("xrserver")
  85     handler.register_introspection_functions()
  86     handler.register_multicall_functions()
  87     handler.handle_request()

Discussion

This could be improved. Some ideas:

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

  • Perhaps perform some sort of caching, to speed up invocation.

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

AutoXmlRpcCgi (last edited 2009-12-03 23:19:57 by vpn-8061f549)

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