Zope3的XML-RPC方法内省支持

zope.app.xmlrpcintrospection的Python项目详细描述


这个zope 3包提供了一个xml-rpc内省机制。

详细文档

xmlrpc内省

现在什么是内省?

这个zope 3包提供了一个xmlrpcintropection机制, 定义如下:

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

它注册了三个新的xmlrpc方法:

  • 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.
如何使用它?

基本上,如果您想在xmlrpcview中添加内省,您只需 必须为视图的每个方法添加一个decorator,它指定 方法的类型和参数类型。

这个decorator称为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()将是可内省的。(以下是完整的例子,grep) 对于(*)

它是如何工作的?

它基于apidoc包提供的内省机制。

*撕裂表单xmlrpc文档*

让我们编写一个返回文件夹列表的视图:

>>> class FolderListing:
...     def contents(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="contents"
...       class="zope.app.xmlrpcintrospection.README.FolderListing"
...       permission="zope.ManageContent"
...       />
... </configure>
... """)

现在,我们将向根文件夹添加一些项目:

>>> 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
...

并调用xmlrpc方法:

>>> 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>

*撕裂表单的结尾xmlrpc doctests*

现在我们要对这个观点进行反思。 我们添加三个新的xmlrcp方法 内省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>
... """)
它们链接到xmlrpcintrospection类,实际上
知道如何查找所有接口

并调用xmlrpc方法,它应该列出内容方法:

>>> 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>

让我们尝试添加另一个方法,如果它被列出的话…

>>> 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>

不,我们要测试methodhelp和methodsignature,以检查它是否返回,

  • The method doc
  • The list of attributes

在rpc中,属性列表必须以数组的形式返回:

[返回类型,参数1类型,参数2类型]

因为在python中,方法返回类型不能有静态类型, 我们在这里介绍一种基于decorator的新机制,它让xmlrpcview 开发者添加自己的签名。

如果没有签名,则返回一个默认列表:

[无,无,无…]

decorator向函数objet附加了两个新参数, 去拿回签名。

>>> 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)

让我们试着找回签名:

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

该方法仍可以根据需要调用:

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

让我们试试修饰和非修饰方法签名(*):

>>> 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>
... """)

现在让我们尝试获取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>

现在让我们尝试获取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>

最后,但并非最不重要的是,方法帮助:

>>> 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>

变化

3.5.1(2010-02-06)

  • 通过包含zope.login修复测试
  • 包括来自zope.app.securitypolicy.browser.tests的ftesting.zcml
  • 包含zope.securitypolicy中的meta.zcml

3.5.0(2009-02-01)

  • zope.site更新zope.app.folder

3.4.0(2007-11-03)

  • 独立于主zope树的初始发布。

欢迎加入QQ群-->: 979659372 Python中文网_新手群

推荐PyPI第三方库


热门话题
在reducer中迭代自定义可写组件时出现java问题   属性文件中属性的java命名约定   任务链关闭的java Executor服务   java从Eclipse中的字段生成多个构造函数   java通过继承读取Json   java在不知道密钥的情况下解析json   java camel cxf如何在电子邮件中发送soap请求响应   java程序似乎跳过了if语句的一部分,在移回正确位置之前先移到else语句   测试简单的Java加密/解密inputFileName不存在   java从Jenkins REST API获取所有作业的所有构建的构建细节   java基本包装器和静态“类型”类对象   在WebSphere8.5上部署java代码   java对象相等(对象引用“=”)   java MongoDB整型字段到枚举的转换   每次我重新导入gradle时,IntelliJ都会不断重置Java设置   类型使用键或索引从Java中的数据类型检索值   在Java的列表接口中需要listIterator()和iterator()是什么?