zope3的json-rpc服务器和客户端实现

z3c.jsonrpc的Python项目详细描述


详细文档

jsonrpc

json是javascript对象表示法。JSON-RPC执行相同的服务 作为XML-RPC,除了传输是JSON而不是XML。

非常感谢Jim Washington在zif.jsonserver上所做的工作。此项目使用 吉姆写了很多代码。我实现了一个附加的python jsonrpc代理 可以与服务器通信。这意味着我们可以使用这个库调用 从python到python的json。json-rpc代理使用类似的模式,如 XML-RPC实现。

另外还有一个xmlhttp和json javascript实现 为javascript提供json-rpc代理实现。

此项目提供了建议的请求类型"application/json"。请求 类型"application/json rpc"是受支持的,只要它不是正式弃用的。

这个项目的目标是提供一个json-rpc实现。简单的 不支持使用browserrequest处理json调用的浏览器视图 通过这个包裹。我仍然不确定这是好是坏 我将带着这个包裹前往的方向。

我的一些目标是现在,但如果我能理解的话,将来可能会改变 关于json的所有概念,例如jspon、json p、crosssite等:

  • 提供一种安全的方法来处理从客户端到服务器的json调用。 我希望有几天我们能实现jsonrequest。Crosssite似乎使用了 插话概念
  • 简单的pythonic实现
  • 与jquery一起使用(请参见http://www.jquery.org rel="nofollow">http://www.jquery.org)。
  • 除jquery和基本zope包外,没有其他依赖项。
  • 测试良好(javascript现在不是这种情况)

关于json

有关json的更多信息,请访问www.json.org。

有关详细信息,请参见http://json-rpc.org/wd/json-rpc-1-1-wd-20060807.html" rel="nofollow">http://json-rpc.org/wd/json-rpc-1-1-wd-20060807.html。 关于JSON 1.1规范。

此软件包不能执行的操作

json和这个包有不同的限制。这个包裹现在可以 不处理以下任务:

  • 处理文件上载
  • 处理GET请求

注意,jsonrpcrequest实现基于ihttprequest,这个 也就是说,如果您调用它们,就没有其他可用的浏览器页 python,例如getmultiadapter((context,request),name='myviewname')。这是 明确地这样做。如果你想使用这样的浏览器页面的内容 在json请求/调用中,您可以继承皮肤形式ijsonrpclayer和 ibrowserrequest并注册此自定义层的json-rpc视图。

json-rpc服务器

json服务器查找内容类型"application/json",并处理 请求为json-rpc。json的官方mime类型是"application/json" 旧的内容类型application/json rpc也受支持。

让我们定义一个内容对象:

< Buff行情>
>>> import zope.interface
>>> class IDemoContent(zope.interface.Interface):
...     """Demo content interface."""
>>> import persistent
>>> class DemoContent(persistent.Persistent):
...     """Demo content."""
...     zope.interface.implements(IDemoContent)

并定义一个jsonrpc方法视图:

< Buff行情>
>>> from z3c.jsonrpc import publisher
>>> class DemoView(publisher.MethodPublisher):
...     """Sample JSON view."""
...
...     def hello(self):
...         return u"Hello World"
...
...     def greeting(self, name):
...         return u"Hello %s" % name
...
...     def mixedparams(self, prefix, bar=None, foo=None):
...         # Note; keyword arguments can be found in request.form
...         return u"%s %s %s" % (prefix, bar, foo)
...
...     def kws(self, adam=None, foo=None, bar=None):
...         # Note; keyword arguments can be found in request.form
...         a = self.request.get('adam')
...         b = self.request.form.get('foo')
...         c = self.request.form.get('bar')
...         return u"%s %s %s" % (a, b, c)
...
...     def showId(self):
...         return u"The json id is: %s" % self.request.jsonId
...
...     def forceValueError(self):
...         raise ValueError('Something was wrong in server method.')

让我们定义一个内容对象,它是一个容器:

< Buff行情>
>>> import zope.interface
>>> class IDemoContainer(zope.container.interfaces.IReadContainer):
...     """Demo container interface."""
>>> import persistent
>>> from zope.container import btree
>>> class DemoContainer(btree.BTreeContainer):
...     """Demo container."""
...     zope.interface.implements(IDemoContainer)

并定义一个jsonrpc方法视图:

< Buff行情>
>>> from z3c.jsonrpc import publisher
>>> class DemoContainerView(publisher.MethodPublisher):
...     """Sample JSON view."""
...
...     def available(self):
...         return u"Hello World"
...
...     def greeting(self, name):
...         return u"Hello %s" % name
...
...     def mixedparams(self, prefix, foo=None, bar=None):
...         # Note; keyword arguments can be found in request.form
...         return u"%s %s %s" % (prefix, foo, bar)
...
...     def kws(self, adam=None, foo=None, bar=None):
...         # Note; keyword arguments can be found in request.form
...         a = self.request.get('adam')
...         b = self.request.form.get('foo')
...         c = self.request.form.get('bar')
...         return u"%s %s %s" % (a, b, c)
...
...     def showId(self):
...         return u"The json id is: %s" % self.request.jsonId
...
...     def forceValueError(self):
...         raise ValueError('Something was wrong in server method.')

把它们放在假包装下 jsonsamples

< Buff行情>
>>> import sys
>>> sys.modules['custom'] = type('Module', (), {})()
>>> sys.modules['custom'].IDemoContent = IDemoContent
>>> sys.modules['custom'].DemoContent = DemoContent
>>> sys.modules['custom'].DemoView = DemoView
>>> sys.modules['custom'].IDemoContainer = IDemoContainer
>>> sys.modules['custom'].DemoContainer = DemoContainer
>>> sys.modules['custom'].DemoContainerView = DemoContainerView

让我们演示如何注册jsonrpc视图:

< Buff行情>
>>> from zope.configuration import xmlconfig
>>> import z3c.jsonrpc
>>> context = xmlconfig.file('meta.zcml', z3c.jsonrpc)
>>> context = xmlconfig.string("""
... <configure
...     xmlns:z3c="http://namespaces.zope.org/z3c">
...   <z3c:jsonrpc
...       for="custom.IDemoContent"
...       class="custom.DemoView"
...       permission="zope.Public"
...       methods="hello greeting mixedparams kws showId forceValueError"
...       layer="z3c.jsonrpc.testing.IJSONRPCTestSkin"
...       />
... </configure>
... """, context)

让我们演示如何为容器注册jsonrpc视图: (容器类也需要权限配置)

< Buff行情>
>>> import zope.interface
>>> class IDemoContent(zope.interface.Interface):
...     """Demo content interface."""
0

现在,我们将在站点中设置一个内容对象:

< Buff行情>
>>> import zope.interface
>>> class IDemoContent(zope.interface.Interface):
...     """Demo content interface."""
1 现在我们可以从jsonrpc视图调用该方法:

< Buff行情>
>>> import zope.interface
>>> class IDemoContent(zope.interface.Interface):
...     """Demo content interface."""
2

但这不是直觉。让我们看看如何遍历方法 hello 使用遍历器:

< Buff行情>
>>> import zope.interface
>>> class IDemoContent(zope.interface.Interface):
...     """Demo content interface."""
3

现在我们尝试使用测试浏览器访问json-rpc视图方法。正如你所能 看,没有可访问的视图。这是因为jsonrpc视图不是 浏览器视图,不可遍历。错误表明请求工厂 返回到浏览器请求工厂:

< Buff行情>
>>> import zope.interface
>>> class IDemoContent(zope.interface.Interface):
...     """Demo content interface."""
4

测试

如果需要测试jsonrpc视图,可以使用如下所示的测试代理 下面的json-rpc代理部分。

json-rpc代理

json rpc包还提供了一个json-rpc代理实现。这个 实现类似于xmlrpclib中已知的实现,只是它可以 处理JSON而不是XML。

让我们尝试调用之前定义的方法 < Buff行情>

>>> import zope.interface
>>> class IDemoContent(zope.interface.Interface):
...     """Demo content interface."""
5

根据jsonrpc规范中的定义,还允许省略参数 我们需要直接用一个帖子来测试,因为 测试代理总是设置参数。

< Buff行情>
>>> import zope.interface
>>> class IDemoContent(zope.interface.Interface):
...     """Demo content interface."""
6
>>> import zope.interface
>>> class IDemoContent(zope.interface.Interface):
...     """Demo content interface."""
7

现在,让我们使用参数进行远程过程调用:

< Buff行情>
>>> import zope.interface
>>> class IDemoContent(zope.interface.Interface):
...     """Demo content interface."""
8

让我们调用命名参数:

< Buff行情>
>>> import zope.interface
>>> class IDemoContent(zope.interface.Interface):
...     """Demo content interface."""
9

json响应中还有一个 id 。让我们使用这样一个json请求id 在我们的jsonrpcproxy中:

< Buff行情>
>>> import persistent
>>> class DemoContent(persistent.Persistent):
...     """Demo content."""
...     zope.interface.implements(IDemoContent)
0

代理也知道这个id为jsonid:

< Buff行情>
>>> import persistent
>>> class DemoContent(persistent.Persistent):
...     """Demo content."""
...     zope.interface.implements(IDemoContent)
1

json-rpc版本

让我们从版本1.0开始测试不同的json-rpc版本:

< Buff行情>
>>> import persistent
>>> class DemoContent(persistent.Persistent):
...     """Demo content."""
...     zope.interface.implements(IDemoContent)
2
>>> import persistent
>>> class DemoContent(persistent.Persistent):
...     """Demo content."""
...     zope.interface.implements(IDemoContent)
3
>>> import persistent
>>> class DemoContent(persistent.Persistent):
...     """Demo content."""
...     zope.interface.implements(IDemoContent)
4
>>> import persistent
>>> class DemoContent(persistent.Persistent):
...     """Demo content."""
...     zope.interface.implements(IDemoContent)
5
>>> import persistent
>>> class DemoContent(persistent.Persistent):
...     """Demo content."""
...     zope.interface.implements(IDemoContent)
6

现在使用json-rpc 1.1版进行测试:

< Buff行情>
>>> import persistent
>>> class DemoContent(persistent.Persistent):
...     """Demo content."""
...     zope.interface.implements(IDemoContent)
7
>>> import persistent
>>> class DemoContent(persistent.Persistent):
...     """Demo content."""
...     zope.interface.implements(IDemoContent)
8
>>> import persistent
>>> class DemoContent(persistent.Persistent):
...     """Demo content."""
...     zope.interface.implements(IDemoContent)
9
>>> from z3c.jsonrpc import publisher
>>> class DemoView(publisher.MethodPublisher):
...     """Sample JSON view."""
...
...     def hello(self):
...         return u"Hello World"
...
...     def greeting(self, name):
...         return u"Hello %s" % name
...
...     def mixedparams(self, prefix, bar=None, foo=None):
...         # Note; keyword arguments can be found in request.form
...         return u"%s %s %s" % (prefix, bar, foo)
...
...     def kws(self, adam=None, foo=None, bar=None):
...         # Note; keyword arguments can be found in request.form
...         a = self.request.get('adam')
...         b = self.request.form.get('foo')
...         c = self.request.form.get('bar')
...         return u"%s %s %s" % (a, b, c)
...
...     def showId(self):
...         return u"The json id is: %s" % self.request.jsonId
...
...     def forceValueError(self):
...         raise ValueError('Something was wrong in server method.')
0
>>> from z3c.jsonrpc import publisher
>>> class DemoView(publisher.MethodPublisher):
...     """Sample JSON view."""
...
...     def hello(self):
...         return u"Hello World"
...
...     def greeting(self, name):
...         return u"Hello %s" % name
...
...     def mixedparams(self, prefix, bar=None, foo=None):
...         # Note; keyword arguments can be found in request.form
...         return u"%s %s %s" % (prefix, bar, foo)
...
...     def kws(self, adam=None, foo=None, bar=None):
...         # Note; keyword arguments can be found in request.form
...         a = self.request.get('adam')
...         b = self.request.form.get('foo')
...         c = self.request.form.get('bar')
...         return u"%s %s %s" % (a, b, c)
...
...     def showId(self):
...         return u"The json id is: %s" % self.request.jsonId
...
...     def forceValueError(self):
...         raise ValueError('Something was wrong in server method.')
1

现在使用json-rpc 2.0版进行测试:

< Buff行情>
>>> from z3c.jsonrpc import publisher
>>> class DemoView(publisher.MethodPublisher):
...     """Sample JSON view."""
...
...     def hello(self):
...         return u"Hello World"
...
...     def greeting(self, name):
...         return u"Hello %s" % name
...
...     def mixedparams(self, prefix, bar=None, foo=None):
...         # Note; keyword arguments can be found in request.form
...         return u"%s %s %s" % (prefix, bar, foo)
...
...     def kws(self, adam=None, foo=None, bar=None):
...         # Note; keyword arguments can be found in request.form
...         a = self.request.get('adam')
...         b = self.request.form.get('foo')
...         c = self.request.form.get('bar')
...         return u"%s %s %s" % (a, b, c)
...
...     def showId(self):
...         return u"The json id is: %s" % self.request.jsonId
...
...     def forceValueError(self):
...         raise ValueError('Something was wrong in server method.')
2
>>> from z3c.jsonrpc import publisher
>>> class DemoView(publisher.MethodPublisher):
...     """Sample JSON view."""
...
...     def hello(self):
...         return u"Hello World"
...
...     def greeting(self, name):
...         return u"Hello %s" % name
...
...     def mixedparams(self, prefix, bar=None, foo=None):
...         # Note; keyword arguments can be found in request.form
...         return u"%s %s %s" % (prefix, bar, foo)
...
...     def kws(self, adam=None, foo=None, bar=None):
...         # Note; keyword arguments can be found in request.form
...         a = self.request.get('adam')
...         b = self.request.form.get('foo')
...         c = self.request.form.get('bar')
...         return u"%s %s %s" % (a, b, c)
...
...     def showId(self):
...         return u"The json id is: %s" % self.request.jsonId
...
...     def forceValueError(self):
...         raise ValueError('Something was wrong in server method.')
3
>>> from z3c.jsonrpc import publisher
>>> class DemoView(publisher.MethodPublisher):
...     """Sample JSON view."""
...
...     def hello(self):
...         return u"Hello World"
...
...     def greeting(self, name):
...         return u"Hello %s" % name
...
...     def mixedparams(self, prefix, bar=None, foo=None):
...         # Note; keyword arguments can be found in request.form
...         return u"%s %s %s" % (prefix, bar, foo)
...
...     def kws(self, adam=None, foo=None, bar=None):
...         # Note; keyword arguments can be found in request.form
...         a = self.request.get('adam')
...         b = self.request.form.get('foo')
...         c = self.request.form.get('bar')
...         return u"%s %s %s" % (a, b, c)
...
...     def showId(self):
...         return u"The json id is: %s" % self.request.jsonId
...
...     def forceValueError(self):
...         raise ValueError('Something was wrong in server method.')
4
>>> from z3c.jsonrpc import publisher
>>> class DemoView(publisher.MethodPublisher):
...     """Sample JSON view."""
...
...     def hello(self):
...         return u"Hello World"
...
...     def greeting(self, name):
...         return u"Hello %s" % name
...
...     def mixedparams(self, prefix, bar=None, foo=None):
...         # Note; keyword arguments can be found in request.form
...         return u"%s %s %s" % (prefix, bar, foo)
...
...     def kws(self, adam=None, foo=None, bar=None):
...         # Note; keyword arguments can be found in request.form
...         a = self.request.get('adam')
...         b = self.request.form.get('foo')
...         c = self.request.form.get('bar')
...         return u"%s %s %s" % (a, b, c)
...
...     def showId(self):
...         return u"The json id is: %s" % self.request.jsonId
...
...     def forceValueError(self):
...         raise ValueError('Something was wrong in server method.')
5
>>> from z3c.jsonrpc import publisher
>>> class DemoView(publisher.MethodPublisher):
...     """Sample JSON view."""
...
...     def hello(self):
...         return u"Hello World"
...
...     def greeting(self, name):
...         return u"Hello %s" % name
...
...     def mixedparams(self, prefix, bar=None, foo=None):
...         # Note; keyword arguments can be found in request.form
...         return u"%s %s %s" % (prefix, bar, foo)
...
...     def kws(self, adam=None, foo=None, bar=None):
...         # Note; keyword arguments can be found in request.form
...         a = self.request.get('adam')
...         b = self.request.form.get('foo')
...         c = self.request.form.get('bar')
...         return u"%s %s %s" % (a, b, c)
...
...     def showId(self):
...         return u"The json id is: %s" % self.request.jsonId
...
...     def forceValueError(self):
...         raise ValueError('Something was wrong in server method.')
6

混合参数

注意,关键字参数将存储在request.form中。重要的 要知道的是,json-rpc不支持 一个方法调用。

< Buff行情>
>>> from z3c.jsonrpc import publisher
>>> class DemoView(publisher.MethodPublisher):
...     """Sample JSON view."""
...
...     def hello(self):
...         return u"Hello World"
...
...     def greeting(self, name):
...         return u"Hello %s" % name
...
...     def mixedparams(self, prefix, bar=None, foo=None):
...         # Note; keyword arguments can be found in request.form
...         return u"%s %s %s" % (prefix, bar, foo)
...
...     def kws(self, adam=None, foo=None, bar=None):
...         # Note; keyword arguments can be found in request.form
...         a = self.request.get('adam')
...         b = self.request.form.get('foo')
...         c = self.request.form.get('bar')
...         return u"%s %s %s" % (a, b, c)
...
...     def showId(self):
...         return u"The json id is: %s" % self.request.jsonId
...
...     def forceValueError(self):
...         raise ValueError('Something was wrong in server method.')
7
>>> from z3c.jsonrpc import publisher
>>> class DemoView(publisher.MethodPublisher):
...     """Sample JSON view."""
...
...     def hello(self):
...         return u"Hello World"
...
...     def greeting(self, name):
...         return u"Hello %s" % name
...
...     def mixedparams(self, prefix, bar=None, foo=None):
...         # Note; keyword arguments can be found in request.form
...         return u"%s %s %s" % (prefix, bar, foo)
...
...     def kws(self, adam=None, foo=None, bar=None):
...         # Note; keyword arguments can be found in request.form
...         a = self.request.get('adam')
...         b = self.request.form.get('foo')
...         c = self.request.form.get('bar')
...         return u"%s %s %s" % (a, b, c)
...
...     def showId(self):
...         return u"The json id is: %s" % self.request.jsonId
...
...     def forceValueError(self):
...         raise ValueError('Something was wrong in server method.')
8
>>> from z3c.jsonrpc import publisher
>>> class DemoView(publisher.MethodPublisher):
...     """Sample JSON view."""
...
...     def hello(self):
...         return u"Hello World"
...
...     def greeting(self, name):
...         return u"Hello %s" % name
...
...     def mixedparams(self, prefix, bar=None, foo=None):
...         # Note; keyword arguments can be found in request.form
...         return u"%s %s %s" % (prefix, bar, foo)
...
...     def kws(self, adam=None, foo=None, bar=None):
...         # Note; keyword arguments can be found in request.form
...         a = self.request.get('adam')
...         b = self.request.form.get('foo')
...         c = self.request.form.get('bar')
...         return u"%s %s %s" % (a, b, c)
...
...     def showId(self):
...         return u"The json id is: %s" % self.request.jsonId
...
...     def forceValueError(self):
...         raise ValueError('Something was wrong in server method.')
9

错误处理

看看如果服务器引发异常会发生什么。我们会得到回应的 附加错误内容的错误:

< Buff行情>
>>> import zope.interface
>>> class IDemoContainer(zope.container.interfaces.IReadContainer):
...     """Demo container interface."""
0

错误内容如下:

< Buff行情>
>>> import zope.interface
>>> class IDemoContainer(zope.container.interfaces.IReadContainer):
...     """Demo container interface."""
1

下一次成功调用时将重置error属性:

< Buff行情>
>>> import zope.interface
>>> class IDemoContainer(zope.container.interfaces.IReadContainer):
...     """Demo container interface."""
2

现在我们用一个伪造的jsonreader强制一个响应者。但首先我们 需要更换ijsonreader实用程序:

< Buff行情>
>>> import zope.interface
>>> class IDemoContainer(zope.container.interfaces.IReadContainer):
...     """Demo container interface."""
3

同时设置站点挂钩:

< Buff行情>
>>> import zope.interface
>>> class IDemoContainer(zope.container.interfaces.IReadContainer):
...     """Demo container interface."""
4

只需调用一个方法,这将引发一个响应错误:

< Buff行情>
>>> import zope.interface
>>> class IDemoContainer(zope.container.interfaces.IReadContainer):
...     """Demo container interface."""
5

错误消息也存储在代理中:

< Buff行情>
>>> import zope.interface
>>> class IDemoContainer(zope.container.interfaces.IReadContainer):
...     """Demo container interface."""
6
运输

我们在这里使用jsonrpctestproxy进行测试。这个json-rpc代理是一个包装器 对于原始的jsonrpcproxy,添加了handleerrors支持和一个特殊的 使用测试调用方的传输层。你可以用不同的 在实际用例中z3c.json.transport模块中定义的传输层 以及默认的jsonrpcproxy实现。

清理

现在我们需要清理自定义模块。

< Buff行情>
>>> import zope.interface
>>> class IDemoContainer(zope.container.interfaces.IReadContainer):
...     """Demo container interface."""
7

指令

jsonrpc指令

演示如何使用jsonrpc指令。注册的元配置 T指令。

< Buff行情>
>>> import zope.interface
>>> class IDemoContainer(zope.container.interfaces.IReadContainer):
...     """Demo container interface."""
8

现在在 z3c:jsonrpc中注册测试模块中定义的视图 指令:

< Buff行情>
>>> import zope.interface
>>> class IDemoContainer(zope.container.interfaces.IReadContainer):
...     """Demo container interface."""
9

让我们检查该视图是否注册为适配器:

< Buff行情>
>>> import persistent
>>> from zope.container import btree
0

我们也可以使用层接口,它将限制我们的视图注册 特定的请求类型。提供这样的请求类型层:

< Buff行情>
>>> import persistent
>>> from zope.container import btree
1

并注册一个新的json-rpc视图:

< Buff行情>
>>> import persistent
>>> from zope.container import btree
2

设置新的内容存根:

< Buff行情>
>>> import persistent
>>> from zope.container import btree
3

并测试新层中的视图:

< Buff行情>
>>> import persistent
>>> from zope.container import btree
4

注意,对象B不知道默认请求层中的视图:

< Buff行情>
>>> import persistent
>>> from zope.container import btree
5

setDefaultJsonRpcskin

< Buff行情>
>>> import persistent
>>> from zope.container import btree
6
>>> import persistent
>>> from zope.container import btree
7

在设置默认请求之前,我们尝试为 要求:

< Buff行情>
>>> import persistent
>>> from zope.container import btree
8

我们的请求不应提供任何默认KIN,因为我们没有注册任何:

< Buff行情>
>>> import persistent
>>> from zope.container import btree
9

现在我们注册一个默认皮肤:

< Buff行情>
>>> class DemoContainer(btree.BTreeContainer):
...     """Demo container."""
...     zope.interface.implements(IDemoContainer)
0

我们可以从适配器注册表中查找默认皮肤:

< Buff行情>
>>> class DemoContainer(btree.BTreeContainer):
...     """Demo container."""
...     zope.interface.implements(IDemoContainer)
1

因为我们有一个默认的皮肤实用程序注册为 请求,新的请求实例应提供默认皮肤:

< Buff行情>
>>> class DemoContainer(btree.BTreeContainer):
...     """Demo container."""
...     zope.interface.implements(IDemoContainer)
2

我们可以通过查找皮肤类型获得应用的默认皮肤:

< Buff行情>
>>> class DemoContainer(btree.BTreeContainer):
...     """Demo container."""
...     zope.interface.implements(IDemoContainer)
3

更改

0.7.2(2013-10-11)

  • handleexception :提供人类可读的回溯

0.7.1(2012-11-27)

  • 修复jsonrpctesttransport以包含请求完整主机。 直到现在它才吃掉了港口。

0.7.0(2012-03-25)

  • 修复:为publisher.processinputs中的parseerror添加了缺少的异常导入
  • 从python导入doctest

0.6.0(2010-01-27)

  • 清除设置依赖项,调整ftesting.zcml
  • 调整覆盖率报告设置
  • 实现了与zopepublication一起工作的错误视图概念
  • 为已知的zope和json-rpc错误实现了默认错误视图
  • 在响应中使用directresult
  • 删除了未经身份验证的错误视图。这不起作用,需要 客户端使用的Java脚本库支持的自定义概念 边

版本0.5.4(2009-04-07)

  • 处理jsonrpc请求中的空参数和无现有参数

版本0.5.3(2009-03-10)

  • 修复:在zope.publisher中反映皮肤查找更改。使用新的skinnable 概念。
  • 修正:默认皮肤没有根据继承的概念应用 来自zope.publisher.browser实现,因为我们的json-rpc请求 不提供ibrowserrequest。添加了将应用给定 创建请求实例期间的idefaultskin。

版本0.5.2(2009-02-24)

  • 为所有json-rpc版本添加了测试
  • 功能:实现了defaultjsonrpcskin指令
  • 特性:支持所有jsonrpc版本的非位置参数。有 现在,在处理所有受支持版本的方法参数方面没有区别。
  • < DL>
    修复:对于jsonrpc 1.1版:
    > UL>
  • 成功时不能提供"error"属性
  • 如果出现错误,不得提供"result"属性
  • 修正:从buildout.cfg中删除了z3c.json的开发路径
  • 修复:publisher将版本id作为字符串而不是浮点数进行检查
  • 特点:IMPLemented JSON-RPC2.0规范。使用JSON-RPC2.0版本作为 违约。可选可设置版本1.0和1.1。见JSON-RPC2.0 有关详细信息的规范。
  • 功能:添加了JSON-RPC异常的初始版本。
  • 添加了显式测试清理,因为某些zope测试更改遗留在 旧连接的全局适配器注册表
  • 删除了测试设置中未使用的对z3c.layer的依赖关系
  • 删除了对z3c.i18n的未使用依赖项。
  • 版本0.5.1(2008-01-24)

    • 改善元数据。
    • bug:皮肤代码依赖于后来才发布的api 还原。

    版本0.5.0(2008-01-21)

    • 初始版本

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

    推荐PyPI第三方库


    热门话题
    java在一个问题被连续正确回答三次/并添加差异后,我如何将程序循环回开始   Java中未实例化的匿名类   java如何在Android中录制视频,只允许横向模式和最长时间录制时间   java从另一个活动发送实时消息   多线程java线程和互斥   java禁用Spring安全日志   JAVA伊奥。StreamCorruptedException:在与子级和父级ProcessBuilder通信时写入子级中的标准输出时,流头无效   使用Java(HttpURLConnection)对Restheart进行身份验证(对于Mongodb)   java如何解决Jenkins中的SAXParseException?   java为什么我需要mockito来测试Spring应用程序?   计算sin-cos和tan时缺乏精度(java)   java Hibernate。不同项目中相同一对一映射的不同行为   java图像滑块:如何使用JavaFX将图像放在另一个图像上   java Mockito在使用when时抛出NotAMockException   http Java servlet发送回响应