【问题标题】:Python SUDS TypeNotFound with complex type whose name starts with "__"名称以“__”开头的复杂类型的 Python SUDS TypeNotFound
【发布时间】:2015-11-18 19:54:44
【问题描述】:

我在 Python SUDS 中遇到了另一个可怕的 TypeNotFound 错误(Python 2.7,suds-jurko==0.6)

这些是 XSD 的相关部分:

<xs:complexType final="extension restriction" name="requestHeader">
    <xs:sequence>
        <xs:element minOccurs="0" name="type" type="tns:requestType"/>
        <xs:element minOccurs="0" name="userID" type="xs:string"/>
        <xs:element minOccurs="0" name="sessionID" type="xs:string"/>
    </xs:sequence>
</xs:complexType>
<xs:complexType final="extension restriction" name="requestType">
    <xs:sequence>
        <xs:element name="__value" type="xs:int"/>
    </xs:sequence>
</xs:complexType>

WSDL 正确导入 XSD,所以我不相信 Doctor 会提供帮助:

<wsdl:definitions 
    name="FooBarService" 
    targetNamespace="foo.bar.ns" 
    xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" 
    xmlns:tns="foo.bar.ns" 
    xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
    xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/">
<schema xmlns="http://www.w3.org/2001/XMLSchema">
<import namespace="foo.bar.ns" schemaLocation="someschemafile.xsd"/>
<import namespace="http://jaxb.dev.java.net/array" schemaLocation="someschemafile2.xsd"/>

还有someschemafile.xsd:

<xs:schema 
    xmlns:xs="http://www.w3.org/2001/XMLSchema" 
    xmlns:ns1="http://jaxb.dev.java.net/array" 
    xmlns:tns="foo.bar.ns" 
    attributeFormDefault="unqualified" 
    elementFormDefault="unqualified" 
    targetNamespace="foo.bar.ns">

然后我创建requestHeader 和requestType:

q = soap_client.factory.create('requestHeader')
print q

(requestHeader){
    type = 
    (requestType){
        __value = None
    }
    userID = None
    sessionID = None
}

然后:

q.type = soap_client.factory.create('requestType')
q.type.__value = 42
q.userID = "foo"
q.sessionID = "bar"
print q

(requestHeader){
    type = 
        (requestType){
            __value = 42
        }   
    userID = "foo"
    sessionID = "bar"
}

然后我尝试调用使用requestHeader 的方法,然后我得到:

TypeNotFound(u"Type not found: '__value'",)

我也试过这个:

q = {
    'type': 42,
    'userID':  "foo",
    'sessionID':  "bar"
}

但这会呈现错误的 SOAP 消息:

<header>
    <type>42</type>
    <userID>foo</userID>
    <sessionID>bar</sessionID>
</header>

而不是

<header>
    <type>
        <__value>42</__value>
    </type>
    <userID>foo</userID>
    <sessionID>bar</sessionID>
</header>

最终被服务拒绝。

很抱歉,我无法提供完整的 WSDL 和 XSD,它们受到限制。

如何使 suds 使用 __value 元素创建正确的 SOAP XML?

我正在使用 WSDL 的本地副本,所以我可以更改它,只要它产生正确的 SOAP XML。不过,我不知道要改变什么。

编辑:添加了一些清理过的回溯(在调用 SUDS 方法之前删除了一些东西)request 是 SUDS 对象,其中一个属性的类型是 requestHeader

---------------------------------------------------------------------------
FooClientClass                 Traceback (most recent call last)
<ipython-input-4-8ccf453fe073> in <module>()
----> 1 soap_client.service.someServiceMethod(request)

/home/user/.virtualenvs/foo_project/local/lib/python2.7/site-packages/suds/client.pyc in __call__(self, *args, **kwargs)
    519         client = clientclass(self.client, self.method)
    520         try:
--> 521             return client.invoke(args, kwargs)
    522         except WebFault, e:
    523             if self.faults():

/home/user/.virtualenvs/foo_project/local/lib/python2.7/site-packages/suds/client.pyc in invoke(self, args, kwargs)
    574         timer.start()
    575         binding = self.method.binding.input
--> 576         soapenv = binding.get_message(self.method, args, kwargs)
    577         timer.stop()
    578         metrics.log.debug("message for '%s' created: %s", self.method.name,

/home/user/.virtualenvs/foo_project/local/lib/python2.7/site-packages/suds/bindings/binding.pyc in get_message(self, method, args, kwargs)
    107         content = self.headercontent(method)
    108         header = self.header(content)
--> 109         content = self.bodycontent(method, args, kwargs)
    110         body = self.body(content)
    111         env = self.envelope(header, body)

/home/user/.virtualenvs/foo_project/local/lib/python2.7/site-packages/suds/bindings/document.pyc in bodycontent(self, method, args, kwargs)
     93 
     94         parse_args(method.name, self.param_defs(method), args, kwargs,
---> 95             add_param, self.options().extraArgumentErrors)
     96 
     97         return root

/home/user/.virtualenvs/foo_project/local/lib/python2.7/site-packages/suds/argparser.pyc in parse_args(method_name, param_defs, args, kwargs, external_param_processor, extra_parameter_errors)
     81     """
     82     arg_parser = _ArgParser(method_name, param_defs, external_param_processor)
---> 83     return arg_parser(args, kwargs, extra_parameter_errors)
     84 
     85 

/home/user/.virtualenvs/foo_project/local/lib/python2.7/site-packages/suds/argparser.pyc in __call__(self, args, kwargs, extra_parameter_errors)
    106         self.__init_run(args, kwargs, extra_parameter_errors)
    107         try:
--> 108             self.__process_parameters()
    109             return self.__all_parameters_processed()
    110         finally:

/home/user/.virtualenvs/foo_project/local/lib/python2.7/site-packages/suds/argparser.pyc in __process_parameters(self)
    297         """Collect values for given web service operation input parameters."""
    298         for pdef in self.__param_defs:
--> 299             self.__process_parameter(*pdef)
    300 
    301     def __push_frame(self, ancestry_item):

/home/user/.virtualenvs/foo_project/local/lib/python2.7/site-packages/suds/argparser.pyc in __process_parameter(self, param_name, param_type, ancestry)
    292         self.__stack[-1].process_parameter(param_optional, value is not None)
    293         self.__external_param_processor(param_name, param_type,
--> 294             self.__in_choice_context(), value)
    295 
    296     def __process_parameters(self):

/home/user/.virtualenvs/foo_project/local/lib/python2.7/site-packages/suds/bindings/document.pyc in add_param(param_name, param_type, in_choice_context, value)
     84             # Construct request data for the current input parameter.
     85             pdef = (param_name, param_type)
---> 86             p = self.mkparam(method, pdef, value)
     87             if p is None:
     88                 return

/home/user/.virtualenvs/foo_project/local/lib/python2.7/site-packages/suds/bindings/document.pyc in mkparam(self, method, pdef, object)
    128                 tags.append(self.mkparam(method, pdef, item))
    129             return tags
--> 130         return Binding.mkparam(self, method, pdef, object)
    131 
    132     def param_defs(self, method):

/home/user/.virtualenvs/foo_project/local/lib/python2.7/site-packages/suds/bindings/binding.pyc in mkparam(self, method, pdef, object)
    223         content = Content(tag=pdef[0], value=object, type=pdef[1],
    224             real=pdef[1].resolve())
--> 225         return marshaller.process(content)
    226 
    227     def mkheader(self, method, hdef, object):

/home/user/.virtualenvs/foo_project/local/lib/python2.7/site-packages/suds/mx/core.pyc in process(self, content)
     57         if isinstance(content.value, Property):
     58             root = self.node(content)
---> 59         self.append(document, content)
     60         return document.root()
     61 

/home/user/.virtualenvs/foo_project/local/lib/python2.7/site-packages/suds/mx/core.pyc in append(self, parent, content)
     70         log.debug('appending parent:\n%s\ncontent:\n%s', parent, content)
     71         if self.start(content):
---> 72             self.appender.append(parent, content)
     73             self.end(parent, content)
     74 

/home/user/.virtualenvs/foo_project/local/lib/python2.7/site-packages/suds/mx/appender.pyc in append(self, parent, content)
     86                 appender = candidate_appender
     87                 break
---> 88         appender.append(parent, content)
     89 
     90 

/home/user/.virtualenvs/foo_project/local/lib/python2.7/site-packages/suds/mx/appender.pyc in append(self, parent, content)
    227         for item in object:
    228             cont = Content(tag=item[0], value=item[1])
--> 229             Appender.append(self, child, cont)
    230 
    231 

/home/user/.virtualenvs/foo_project/local/lib/python2.7/site-packages/suds/mx/appender.pyc in append(self, parent, content)
    166         @type content: L{Object}
    167         """
--> 168         self.marshaller.append(parent, content)
    169 
    170 

/home/user/.virtualenvs/foo_project/local/lib/python2.7/site-packages/suds/mx/core.pyc in append(self, parent, content)
     70         log.debug('appending parent:\n%s\ncontent:\n%s', parent, content)
     71         if self.start(content):
---> 72             self.appender.append(parent, content)
     73             self.end(parent, content)
     74 

/home/user/.virtualenvs/foo_project/local/lib/python2.7/site-packages/suds/mx/appender.pyc in append(self, parent, content)
     86                 appender = candidate_appender
     87                 break
---> 88         appender.append(parent, content)
     89 
     90 

/home/user/.virtualenvs/foo_project/local/lib/python2.7/site-packages/suds/mx/appender.pyc in append(self, parent, content)
    227         for item in object:
    228             cont = Content(tag=item[0], value=item[1])
--> 229             Appender.append(self, child, cont)
    230 
    231 

/home/user/.virtualenvs/foo_project/local/lib/python2.7/site-packages/suds/mx/appender.pyc in append(self, parent, content)
    166         @type content: L{Object}
    167         """
--> 168         self.marshaller.append(parent, content)
    169 
    170 

/home/user/.virtualenvs/foo_project/local/lib/python2.7/site-packages/suds/mx/core.pyc in append(self, parent, content)
     70         log.debug('appending parent:\n%s\ncontent:\n%s', parent, content)
     71         if self.start(content):
---> 72             self.appender.append(parent, content)
     73             self.end(parent, content)
     74 

/home/user/.virtualenvs/foo_project/local/lib/python2.7/site-packages/suds/mx/appender.pyc in append(self, parent, content)
     86                 appender = candidate_appender
     87                 break
---> 88         appender.append(parent, content)
     89 
     90 

/home/user/.virtualenvs/foo_project/local/lib/python2.7/site-packages/suds/mx/appender.pyc in append(self, parent, content)
    227         for item in object:
    228             cont = Content(tag=item[0], value=item[1])
--> 229             Appender.append(self, child, cont)
    230 
    231 

/home/user/.virtualenvs/foo_project/local/lib/python2.7/site-packages/suds/mx/appender.pyc in append(self, parent, content)
    166         @type content: L{Object}
    167         """
--> 168         self.marshaller.append(parent, content)
    169 
    170 

/home/user/.virtualenvs/foo_project/local/lib/python2.7/site-packages/suds/mx/core.pyc in append(self, parent, content)
     69         """
     70         log.debug('appending parent:\n%s\ncontent:\n%s', parent, content)
---> 71         if self.start(content):
     72             self.appender.append(parent, content)
     73             self.end(parent, content)

/home/user/.virtualenvs/foo_project/local/lib/python2.7/site-packages/suds/mx/literal.pyc in start(self, content)
     84             content.type = self.resolver.find(name, content.value)
     85             if content.type is None:
---> 86                 raise TypeNotFound(content.tag)
     87         else:
     88             known = None

TypeNotFound(u"Type not found: '__value'",)

【问题讨论】:

  • "然后我尝试调用使用requestHeader的方法,然后我得到:"请显示您正在调用的方法。
  • 您必须记住的是,以__variable 之类的双下划线开头的类变量对于python 中的类来说是私有的(它们实际上是被破坏的而不是真正私有的),这可能是你困难的原因。如果必须,我会说停止使用双下划线或使用一个下划线。通过使用重整名称的麻烦是可能的,但它真的很混乱而且不是pythonic,我会完全不鼓励它。
  • 是的,我知道 Python 中的双下划线,但是……我不是请求的 SOAP API 的作者,我只是在使用它……那是企业 Java 怪物双下划线名称没有任何意义......我会看看我是否可以做一些事情来防止 Python 中的名称修改,也许这就是 SUDS 感到困惑的原因。谢谢
  • @dopstar :我不能真正展示整个方法,但它是这样的:soap_client.service.someMethod(soap_object_with_request_header)
  • 类似什么?我明白,不要显示该方法是如何实现的。只需显示您如何称呼它。或者只显示完整的回溯错误消息,因为它将显示在那里而不是显示最终的错误消息。恐怕这种信息是相当有用的。除非回溯也被“限制”:)

标签: python soap suds


【解决方案1】:

根据@dopstar 的评论,这是由于 SUDS 中的错误而发生的。由于我没有时间尝试在源上修复它,因此我设计了一些丑陋的解决方法

from lxml import etree

etree_object = build_XML_using_etree()

soap_client.service.someServiceMethod(
    __inject={'msg': etree.tostring(etree_object)}
)

丑陋的部分在这里实际上是不可见的,它是编织隐藏在build_XML_using_etree 方法后面的 XML 的逻辑,因为我们不能依赖 SUDS 在这里做。

另一方面,一旦将原始 XML 注入到 SUDS 堆栈中,其他一切都运行良好,所以也许这还不错......

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多