Skip to main content

XML-RPC Method Introspection Support for Zope 3

Project description

This Zope 3 package provides an XML-RPC introspection mechanism.

Detailed Documentation

XMLRPC Introspection

What’s introspection now ?

This Zope 3 package provides an xmlrpcintrospection mechanism, as defined here:

http://xmlrpc-c.sourceforge.net/xmlrpc-howto/xmlrpc-howto-api-introspection.html

It registers three new xmlrpc methods:

  • listMethods(): Lists all xmlrpc methods (ie views) registered for the current object

  • methodHelp(method_name): Returns the method documentation of the given method.

  • methodSignature(method_name): Returns the method documentation of the given method.

How do I use it ?

Basically, if you want to add introspection into your XMLRPCView, you just have to add a decorator for each method of the view, that specifies the return type of the method and the argument types.

The decorator is called xmlrpccallable

>>> from zope.app.xmlrpcintrospection.xmlrpcintrospection import xmlrpccallable
>>> from zope.app.publisher.xmlrpc import XMLRPCView
>>> class MySuperXMLRPCView(XMLRPCView):
...     @xmlrpccallable(str, str, str, str)
...     def myMethod(self, a, b, c):
...         """ my help """
...         return '%s %s, %s, lalalala, you and me, lalalala' % (a, b, c)

myMethod() will then be introspectable. (find a full examples below, grep for (*))

How does it works ?

It is based on introspection mechanisms provided by the apidoc package.

* ripped form xmlrpc doctests *

Let’s write a view that returns a folder listing:

>>> class FolderListing:
...     def contents(self):
...         return list(self.context.keys())

Now we’ll register it as a view:

>>> from zope.configuration import xmlconfig
>>> ignored = xmlconfig.string("""
... <configure
...     xmlns="http://namespaces.zope.org/zope"
...     xmlns:xmlrpc="http://namespaces.zope.org/xmlrpc"
...     >
...   <!-- We only need to do this include in this example,
...        Normally the include has already been done for us. -->
...   <include package="zope.app.publisher.xmlrpc" file="meta.zcml" />
...
...   <xmlrpc:view
...       for="zope.site.interfaces.IFolder"
...       methods="contents"
...       class="zope.app.xmlrpcintrospection.README.FolderListing"
...       permission="zope.ManageContent"
...       />
... </configure>
... """)

Now, we’ll add some items to the root folder:

>>> print http(r"""
... POST /@@contents.html HTTP/1.1
... Authorization: Basic bWdyOm1ncnB3
... Content-Length: 73
... Content-Type: application/x-www-form-urlencoded
...
... type_name=BrowserAdd__zope.site.folder.Folder&new_value=f1""")
HTTP/1.1 303 See Other
...
>>> print http(r"""
... POST /@@contents.html HTTP/1.1
... Authorization: Basic bWdyOm1ncnB3
... Content-Length: 73
... Content-Type: application/x-www-form-urlencoded
...
... type_name=BrowserAdd__zope.site.folder.Folder&new_value=f2""")
HTTP/1.1 303 See Other
...

And call our xmlrpc method:

>>> print http(r"""
... POST / HTTP/1.0
... Authorization: Basic bWdyOm1ncnB3
... Content-Length: 102
... Content-Type: text/xml
...
... <?xml version='1.0'?>
... <methodCall>
... <methodName>contents</methodName>
... <params>
... </params>
... </methodCall>
... """)
HTTP/1.0 200 OK
...
<?xml version='1.0'?>
<methodResponse>
<params>
<param>
<value><array><data>
<value><string>f1</string></value>
<value><string>f2</string></value>
</data></array></value>
</param>
</params>
</methodResponse>
<BLANKLINE>

* end of ripped form xmlrpc doctests *

Now we want to provide to that view introspection. Let’s add three new xmlrcp methods, that published the introspection api.

>>> ignored = xmlconfig.string("""
... <configure
...     xmlns="http://namespaces.zope.org/zope"
...     xmlns:xmlrpc="http://namespaces.zope.org/xmlrpc"
...     >
...   <!-- We only need to do this include in this example,
...        Normally the include has already been done for us. -->
...   <include package="zope.app.publisher.xmlrpc" file="meta.zcml" />
...   <xmlrpc:view
...     for="zope.interface.Interface"
...     methods="listMethods  methodHelp methodSignature"
...     class="zope.app.xmlrpcintrospection.xmlrpcintrospection.XMLRPCIntrospection"
...     permission="zope.Public"
...     />
... </configure>
... """)
They are linked to XMLRPCIntrospection class, that actually

knows how to lookup to all interfaces

And call our xmlrpc method, that should list the content method:

>>> print http(r"""
... POST / HTTP/1.0
... Content-Type: text/xml
...
... <?xml version='1.0'?>
... <methodCall>
... <methodName>listMethods</methodName>
... <params>
... </params>
... </methodCall>
... """, handle_errors=False)
HTTP/1.0 200 OK
...
<?xml version='1.0'?>
<methodResponse>
...
<value><string>contents</string></value>
...
</methodResponse>
<BLANKLINE>

Let’s try to add another method, to se if it gets listed…

>>> class FolderListing2:
...     def contents2(self):
...         return list(self.context.keys())
>>> from zope.configuration import xmlconfig
>>> ignored = xmlconfig.string("""
... <configure
...     xmlns="http://namespaces.zope.org/zope"
...     xmlns:xmlrpc="http://namespaces.zope.org/xmlrpc"
...     >
...   <!-- We only need to do this include in this example,
...        Normally the include has already been done for us. -->
...   <include package="zope.app.publisher.xmlrpc" file="meta.zcml" />
...
...   <xmlrpc:view
...       for="zope.site.interfaces.IFolder"
...       methods="contents2"
...       class="zope.app.xmlrpcintrospection.README.FolderListing2"
...       permission="zope.ManageContent"
...       />
... </configure>
... """)
>>> print http(r"""
... POST / HTTP/1.0
... Content-Type: text/xml
...
... <?xml version='1.0'?>
... <methodCall>
... <methodName>listMethods</methodName>
... <params>
... </params>
... </methodCall>
... """, handle_errors=False)
HTTP/1.0 200 OK
...
<?xml version='1.0'?>
<methodResponse>
...
<value><string>contents</string></value>
<value><string>contents2</string></value>
...
</methodResponse>
<BLANKLINE>

No we want to test methodHelp and methodSignature, to check that it returns,

  • The method doc

  • The list of attributes

In RPC, the list of attributes has to be return in an array of type:

[return type, param1 type, param2 type]

Since in Python we cannot have a static type for the method return type, we introduce here a new mechanism based on a decorator, that let the xmlrpcview developer add his own signature.

If the signature is not given, a defaut list is returned:

[None, None, None…]

The decorator append to the function objet two new parameters, to get back the signature.

>>> from zope.app.xmlrpcintrospection.xmlrpcintrospection import xmlrpccallable
>>> class JacksonFiveRPC:
...     @xmlrpccallable(str, str, str, str)
...     def says(self, a, b, c):
...         return '%s %s, %s, lalalala, you and me, lalalala' % (a, b, c)

Let’s try to get back the signature:

>>> JacksonFiveRPC().says.return_type
<type 'str'>
>>> JacksonFiveRPC().says.parameters_types
(<type 'str'>, <type 'str'>, <type 'str'>)

The method is still callable as needed:

>>> JacksonFiveRPC().says('a', 'b', 'c')
'a b, c, lalalala, you and me, lalalala'

Let’s try out decorated and not decorated methods signatures (*):

>>> class JacksonFiveRPC:
...     @xmlrpccallable(str, str, str, str)
...     def says(self, a, b, c):
...         return '%s %s, %s, lalalala, you and me, lalalala' % (a, b, c)
...     def says_not_decorated(self, a, b, c):
...         return '%s %s, %s, lalalala, you and me, lalalala' % (a, b, c)
>>> from zope.configuration import xmlconfig
>>> ignored = xmlconfig.string("""
... <configure
...     xmlns="http://namespaces.zope.org/zope"
...     xmlns:xmlrpc="http://namespaces.zope.org/xmlrpc"
...     >
...   <!-- We only need to do this include in this example,
...        Normally the include has already been done for us. -->
...   <include package="zope.app.publisher.xmlrpc" file="meta.zcml" />
...
...   <xmlrpc:view
...       for="zope.site.folder.IFolder"
...       methods="says says_not_decorated"
...       class="zope.app.xmlrpcintrospection.README.JacksonFiveRPC"
...       permission="zope.ManageContent"
...       />
... </configure>
... """)

Now let’s try to get the signature for says():

>>> print http(r"""
... POST / HTTP/1.0
... Content-Type: text/xml
...
... <?xml version='1.0'?>
... <methodCall>
... <methodName>methodSignature</methodName>
... <params>
... <param>
... <value>says</value>
... </param>
... </params>
... </methodCall>
... """, handle_errors=False)
HTTP/1.0 200 OK
...
<?xml version='1.0'?>
<methodResponse>
<params>
<param>
<value><array><data>
<value><array><data>
<value><string>str</string></value>
<value><string>str</string></value>
<value><string>str</string></value>
<value><string>str</string></value>
</data></array></value>
</data></array></value>
</param>
</params>
</methodResponse>
<BLANKLINE>

Now let’s try to get the signature for says_not_decorated()`:

>>> print http(r"""
... POST / HTTP/1.0
... Content-Type: text/xml
...
... <?xml version='1.0'?>
... <methodCall>
... <methodName>methodSignature</methodName>
... <params>
... <param>
... <value>says_not_decorated</value>
... </param>
... </params>
... </methodCall>
... """, handle_errors=False)
HTTP/1.0 200 OK
...
<?xml version='1.0'?>
<methodResponse>
<params>
<param>
<value><array><data>
<value><array><data>
<value><string>undef</string></value>
<value><string>undef</string></value>
<value><string>undef</string></value>
<value><string>undef</string></value>
</data></array></value>
</data></array></value>
</param>
</params>
</methodResponse>
<BLANKLINE>

Last, but not least, the method help:

>>> class JacksonFiveRPCDocumented:
...     @xmlrpccallable(str, str, str, str)
...     def says(self, a, b, c):
...         """ this is the help for
...             says()
...         """
...         return '%s %s, %s, lalalala, you and me, lalalala' % (a, b, c)
...     def says_not_documented(self, a, b, c):
...         return '%s %s, %s, lalalala, you and me, lalalala' % (a, b, c)
>>> from zope.configuration import xmlconfig
>>> ignored = xmlconfig.string("""
... <configure
...     xmlns="http://namespaces.zope.org/zope"
...     xmlns:xmlrpc="http://namespaces.zope.org/xmlrpc"
...     >
...   <!-- We only need to do this include in this example,
...        Normally the include has already been done for us. -->
...   <include package="zope.app.publisher.xmlrpc" file="meta.zcml" />
...
...   <xmlrpc:view
...       for="zope.site.folder.IFolder"
...       methods="says says_not_documented"
...       class="zope.app.xmlrpcintrospection.README.JacksonFiveRPCDocumented"
...       permission="zope.ManageContent"
...       />
... </configure>
... """)
>>> print http(r"""
... POST / HTTP/1.0
... Content-Type: text/xml
...
... <?xml version='1.0'?>
... <methodCall>
... <methodName>methodHelp</methodName>
... <params>
... <param>
... <value>says</value>
... </param>
... </params>
... </methodCall>
... """, handle_errors=False)
HTTP/1.0 200 OK
...
<?xml version='1.0'?>
<methodResponse>
<params>
<param>
<value><string> this is the help for
             says()
         </string></value>
</param>
</params>
</methodResponse>
<BLANKLINE>
>>> print http(r"""
... POST / HTTP/1.0
... Content-Type: text/xml
...
... <?xml version='1.0'?>
... <methodCall>
... <methodName>methodHelp</methodName>
... <params>
... <param>
... <value>says_not_documented</value>
... </param>
... </params>
... </methodCall>
... """, handle_errors=False)
HTTP/1.0 200 OK
...
<?xml version='1.0'?>
<methodResponse>
<params>
<param>
<value><string>undef</string></value>
</param>
</params>
</methodResponse>
<BLANKLINE>

CHANGES

3.5.1 (2010-02-06)

  • Fix test by including zope.login

  • Include ftesting.zcml from zope.app.securitypolicy.browser.tests

  • Include meta.zcml from zope.securitypolicy

3.5.0 (2009-02-01)

  • Update zope.app.folder with zope.site.

3.4.0 (2007-11-03)

  • Initial release independent of the main Zope tree.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

zope.app.xmlrpcintrospection-3.5.1.tar.gz (10.3 kB view details)

Uploaded Source

File details

Details for the file zope.app.xmlrpcintrospection-3.5.1.tar.gz.

File metadata

File hashes

Hashes for zope.app.xmlrpcintrospection-3.5.1.tar.gz
Algorithm Hash digest
SHA256 fead926e3f1f7f39bc62f5906634d143973d00b7b34f24e691cc2b5bfe7870a6
MD5 8cf0e7fc13ece3743f96f92d05682d74
BLAKE2b-256 4cb9ec4ad5e62eca449af19c9bb3fb3ef1e0de05a260f0a60e1ca59c9e5e2878

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page