complex types in input, handled ?

Asked by Laurent G. on 2011-08-08

Hi,
I tried to define an operation that take two Complex with :
class Complex(LadonType):
  r = float
  i = float

  def __init__(self, r, i):
    self.r = r
    self.i = i

  def __repr__(self):
    return "(%g+%gj)" % (self.r, self.i)

and return the sum.
Using suds to tests I got the stack_trace in the server while running the client test in another terminal :

Traceback (most recent call last):
  File "/usr/lib/python2.7/site-packages/ladon/server/wsgi_application.py", line 271, in __call__
    output = dispatcher.dispatch_request(request_data,environ)
  File "/usr/lib/python2.7/site-packages/ladon/server/dispatcher.py", line 122, in dispatch_request
    result = self.call_method(method,req_dict,tc,export_dict)
  File "/usr/lib/python2.7/site-packages/ladon/server/dispatcher.py", line 61, in call_method
    args += [arg['type'](prime_dict=val,tc=tc)]
TypeError: __init__() got an unexpected keyword argument 'prime_dict'

It may be that suds shows me the exception it got back from the server. Hum, that's when I set
client.set_options(retxml=True)
if I don't, I get :

  File "suds_tests.py", line 17, in <module>
    res_comp = client.service.add_complex(a, b)
  File "/usr/lib/python2.7/site-packages/suds/client.py", line 542, in __call__
    return client.invoke(args, kwargs)
  File "/usr/lib/python2.7/site-packages/suds/client.py", line 602, in invoke
    result = self.send(soapenv)
  File "/usr/lib/python2.7/site-packages/suds/client.py", line 643, in send
    result = self.succeeded(binding, reply.message)
  File "/usr/lib/python2.7/site-packages/suds/client.py", line 678, in succeeded
    reply, result = binding.get_reply(self.method, reply)
  File "/usr/lib/python2.7/site-packages/suds/bindings/binding.py", line 145, in get_reply
    replyroot = sax.parse(string=reply)
  File "/usr/lib/python2.7/site-packages/suds/sax/parser.py", line 136, in parse
    sax.parse(source)
  File "/usr/lib/python2.7/xml/sax/expatreader.py", line 107, in parse
    xmlreader.IncrementalParser.parse(self, source)
  File "/usr/lib/python2.7/xml/sax/xmlreader.py", line 123, in parse
    self.feed(buffer)
  File "/usr/lib/python2.7/xml/sax/expatreader.py", line 211, in feed
    self._err_handler.fatalError(exc)
  File "/usr/lib/python2.7/xml/sax/handler.py", line 38, in fatalError
    raise exception
xml.sax._exceptions.SAXParseException: <unknown>:1:0: syntax error

Is there a way to tell the server to leave a log of requests and responses ?

Thanks in advance.

Question information

Language:
English Edit question
Status:
Solved
For:
ladon Edit question
Assignee:
No assignee Edit question
Last query:
2011-08-25
Last reply:
2012-01-08
jsgaarde (jakob-simon-gaarde) said : #1

Sorry Laurent - I have been busy releasing version 0.6.1.

I will answer you within the next couple of hours :-)

Best regards Jakob

jsgaarde (jakob-simon-gaarde) said : #2

Hi Laurent.

Just so I don't misunderstand what you want to do, could you please paste the whole service?

Best regarda
Jakob Simon-Gaarde

Laurent G. (lauranger-x) said : #3

Le 09/08/2011 15:35, jsgaarde a écrit :
> Your question #167369 on ladon changed:
> https://answers.launchpad.net/ladon/+question/167369
>
> Status: Open => Needs information
>
> jsgaarde requested more information:
> Hi Laurent.
>
> Just so I don't misunderstand what you want to do, could you please
> paste the whole service?
>
> Best regarda
> Jakob Simon-Gaarde

Hi Jakob,

I hope attachments are taken into account.
Don't mind being that quick to answer me : you are alone and you owe me
nothing ;-)
In fact there are two question :
1) How can I see the incoming and outgoing http chunks or at least the
xml, at least for the soap/wsdl exposition ? Is there any easy tweak ?
2) Are incoming structures handled ?

Thanks in advance.

Laurent G.

jsgaarde (jakob-simon-gaarde) said : #4

Hi Laurant.

The reason you get the exception you get is because you override the default init method from LadonType. The ladon framework must be able to create objects based on LadonType without supplying required positional arguments. It also must be able to create objects using the prime_dict keyword argument.
You can however implement __init__ methods for your LadonType based classes as long as you make sure to comply with these conditions. What you have to do is make sure your LadonType specialization sends keword arguments on to LadonType's __init__ method and that all your specialization arguments have default values, example:

from ladon.ladonizer import ladonize
from ladon.types.ladontype import LadonType

class ComplexType(LadonType):

        r = float
        i = float

        def __init__(self,r=None, i=None, **kw):
                # ASSIGNEMTS
                # Class-local assignments
                self.r = r
                self.i = i
                # prime_dict based assignments
                LadonType.__init__(self,**kw) # Call the LadonType.__init__() method after local assignments passing on **kw

                # POST ASSIGNMENT LOGIC
                self.do_some_post_calculations()

        def do_some_post_calculations(self):
                # Dummy operation for the example
                self.r += 21.6

        def __repr__(self):
                return "(%g+%gj)" % (self.r, self.i)

class TestService(object):

        @ladonize(ComplexType,rtype=ComplexType)
        def complex(self,c):
                return ComplexType(2.3,0.5)

jsgaarde (jakob-simon-gaarde) said : #5

ups - btw the above example only works with ladon 0.6.1 - if you are using ladon prior to 0.6.1 your __init__() must be something like this:

from ladon.ladonizer import ladonize
from ladon.types.ladontype import LadonType

class ComplexType(LadonType):

        r = float
        i = float

        def __init__(self,prime_dict=None,tc=None,export_dict=None,r=None, i=None, **kw):
                # ASSIGNEMTS
                # Class-local assignments
                self.r = r
                self.i = i
                # prime_dict based assignments
                LadonType.__init__(self,prime_dict=prime_dict,tc=tc,export_dict=export_dict)

                # POST ASSIGNMENT LOGIC
                self.do_some_post_calculations()

 . . .

Best Regards
Jakob Simon-Gaarde

jsgaarde (jakob-simon-gaarde) said : #6

Hi Again.

> 1) How can I see the incoming and outgoing http chunks or at least the
> xml, at least for the soap/wsdl exposition ? Is there any easy tweak ?
> 2) Are incoming structures handled ?

Can you please create a new question thread per question, that way the question threads are better structured :-)

Best Regards
Jakob Simon-Gaarde

jsgaarde (jakob-simon-gaarde) said : #7

Hi Laurent.

Did my answer solve your problem with the ComplexType example?

Best Regards
Jakob Simon-Gaarde

BTW: you can use Wireshark or tcpdump to see incomming and outgoing messages.

I don't know what you mean with your question 2, sorry :-)

Best Regards
Jakob Simon-Gaarde

Laurent G. (lauranger-x) said : #8

Le 11/08/2011 00:51, jsgaarde a écrit :
> Your question #167369 on ladon changed:
> https://answers.launchpad.net/ladon/+question/167369
>
> jsgaarde proposed the following answer:
> Hi Laurent.
>
> Did my answer solve your problem with the ComplexType example?
>
> Best Regards
> Jakob Simon-Gaarde
>
> BTW: you can use Wireshark or tcpdump to see incomming and outgoing
> messages.
>
> I don't know what you mean with your question 2, sorry :-)
>
> Best Regards
> Jakob Simon-Gaarde

Hi Jakob,
For question 2) you just have answered in previous mails : you also aim
at handling structures in incoming messages, but we had to wait for
0.6.1 to have this handling in effect.
For question 1) I've never used neither tcpdump nor wireshark till then
but I can learn(hopefully). My qustion was about possible existence in
ladon of a command line options or a light tweak in the code to give
such information. Appearently there is none and I'd have to use any of
the two softwares you cited. This is a sound answer from you, at least
to my point of view. Even though I had prefered just had an option to
ladon2.7ctl ;-)
Have a nice end of week, Jakob.
Laurent G.

jsgaarde (jakob-simon-gaarde) said : #9

Hi Laurent.

Oh so you meant multipart messages - yes that is the new big thing in 0.6.1, and JSON-WSP handles attachments better than any other webservices I have ever heard of - so try it out. Unfortunately - as you may know - SOAP has lousy support for attachments, the worst part being that you must pre-define and name every attachment a method will recieve or send. This makes it difficult to create webservices where users descide themselves how many attachments to send in one request.

Right now there only exists JSON-WSP clients for Python and javascript, but me and my "Ladon for PHP" co-developer are planning clients for C++, Java, C# and an online JSON-WSP client that can load JSON-WSP descriptions and serve up a nice UI for testing methods. These new clients are our top priority the next month.

If you are curious to how attachments work in JSON-WSP take a look at:
http://en.wikipedia.org/wiki/Jsonwsp#Attachments

You study and try out attachments easilly:
http://ladonize.org/index.php/Python_Example#Install_local_examples

Best Regards
Jakob Simon-Gaarde

jsgaarde (jakob-simon-gaarde) said : #10

Seems all questions were solved - so I am setting status solved

Laurent G. (lauranger-x) said : #11

Hi jakob,

Found some time to retry.
Sorry no better. I used tcp dump as you suggested. Found subs loggig things too.

ERROR:suds.client:<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:ns3="urn:Calculator" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns0="http://schemas.xmlsoap.org/soap/encoding/" xmlns:ns1="http://schemas.xmlsoap.org/soap/envelope/" xmlns:ns2="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" SOAP-ENV:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
   <SOAP-ENV:Header/>
   <ns1:Body>
      <ns3:add_complex>
         <a xsi:type="ns3:Complex">
            <i xsi:type="ns2:decimal">0</i>
            <r xsi:type="ns2:decimal">1</r>
         </a>
         <b xsi:type="ns3:Complex">
            <i xsi:type="ns2:decimal">1</i>
            <r xsi:type="ns2:decimal">0</r>
         </b>
      </ns3:add_complex>
   </ns1:Body>
</SOAP-ENV:Envelope>
DEBUG:suds.client:http failed:
Traceback (most recent call last):
  File "/home/laurent/lib/python/ladon-0.6.1-py2.7.egg/ladon/server/wsgi_application.py", line 356, in __call__
    response_part = dispatcher.dispatch_request(request_data,environ)
  File "/home/laurent/lib/python/ladon-0.6.1-py2.7.egg/ladon/server/dispatcher.py", line 159, in dispatch_request
    res_dict = self.result_to_dict(method,result,tc,export_dict['response_attachments'])
  File "/home/laurent/lib/python/ladon-0.6.1-py2.7.egg/ladon/server/dispatcher.py", line 142, in result_to_dict
    res_dict['result'] = result.__dict__(tc,response_attachments)
  File "/home/laurent/lib/python/ladon-0.6.1-py2.7.egg/ladon/types/ladontype.py", line 198, in __dict__
    res_dict[attr_name] = tc.to_unicode_string(attr_val,attr_type)
  File "/home/laurent/lib/python/ladon-0.6.1-py2.7.egg/ladon/types/typeconverter.py", line 68, in to_unicode_string
    if expected_typ not in safe_conversions[typ]:
KeyError: <type 'NoneType'>

with

class Complex(LadonType):
  r = float
  i = float

  def __init__(self,r=None, i=None, **kw):
    # ASSIGNEMTS
    # Class-local assignments
    self.r = r
    self.i = i
    # prime_dict based assignments
    LadonType.__init__(self,**kw)

  def __repr__(self):
    return "(%g+%gj)" % (self.r, self.i)

class Calculator(object):
#[...SNIP...]
  @ladonize(Complex, Complex, rtype=Complex)
  def add_complex(self, a, b):
    """ Add two complex numbers and return the result
    @param a: 1st complex number
    @param b: 2nd complex number
    @rtype: The result of the addition
    """
    #ret = complex(a.r, a.i) + complex(b.r, b.i)
    #return Complex(ret.real, ret.imag)
    return a

and "live" description gives

<definitions name="Calculator" targetNamespace="urn:Calculator">

<types>

<schema targetNamespace="urn:Calculator">
<import namespace="http://schemas.xmlsoap.org/soap/encoding/"/>

<complexType name="ArrayOfint">

<complexContent>

<restriction base="SOAP-ENC:Array">

<sequence>
<element maxOccurs="unbounded" minOccurs="0" name="item" type="xsd:long"/>
</sequence>
<attribute WSDL:arrayType="xsd:long[]" ref="SOAP-ENC:arrayType"/>
</restriction>
</complexContent>
</complexType>

<complexType name="Complex">

<sequence>
<element maxOccurs="1" minOccurs="1" name="i" type="xsd:decimal"/>
<element maxOccurs="1" minOccurs="1" name="r" type="xsd:decimal"/>
</sequence>
</complexType>
</schema>
</types>

<message name="add">
<part name="a" type="xsd:long"/>
<part name="b" type="xsd:long"/>
</message>

<message name="addResponse">
<part name="result" type="xsd:long"/>
</message>

<message name="add_complex">
<part name="a" type="ns1:Complex"/>
<part name="b" type="ns1:Complex"/>
</message>

<message name="add_complexResponse">
<part maxOccurs="1" minOccurs="1" name="i" type="xsd:decimal"/>
<part maxOccurs="1" minOccurs="1" name="r" type="xsd:decimal"/>
</message>

<message name="add_many">
<part name="args" type="ns1:ArrayOfint"/>
</message>

<message name="add_manyResponse">
<part name="result" type="xsd:long"/>
</message>

<portType name="CalculatorPortType">

<operation name="add">
<documentation>Add two integers together and return the result.
</documentation>
<input message="tns:add"/>
<output message="tns:addResponse"/>
</operation>

<operation name="add_complex">
<documentation>Add two complex numbers and return the result</documentation>
<input message="tns:add_complex"/>
<output message="tns:add_complexResponse"/>
</operation>

<operation name="add_many">
<documentation>Add integers together and return the result
</documentation>
<input message="tns:add_many"/>
<output message="tns:add_manyResponse"/>
</operation>
</portType>

Hope I don't bother you too much.

Regards.

jsgaarde (jakob-simon-gaarde) said : #12

Hi Laurent.

1. What version of Ladon are you using?
2. Could you http://pastebin.com the whole service?

Best regards
Jakob Simon-Gaarde

Laurent G. (lauranger-x) said : #13

Le 24/08/2011 08:45, jsgaarde a écrit :
> Your question #167369 on ladon changed:
> https://answers.launchpad.net/ladon/+question/167369
>
> Status: Open => Needs information
>
> jsgaarde requested more information:
> Hi Laurent.
>
> 1. What version of Ladon are you using?
> 2. Could you http://pastebin.com the whole service?
>
> Best regards
> Jakob Simon-Gaarde
>

Hi Jakob,

I tried to use ladon 0.6.1

For the server side script:
http://pastebin.com/XMFZZySB

for the suds client:
http://pastebin.com/xM98wdMs

for the suds output:
http://pastebin.com/kKt8XFzR

Hth

Laurent G.

jsgaarde (jakob-simon-gaarde) said : #14

Hi Laurent.

I released a new version of Ladon yesterday that solves the problem with your add_complex method: http://pypi.python.org/pypi/ladon#new-in-0-6-2

I found that people were having some difficulties with the SOAP interface and there were some minor and a major bug. So I sat down and completely rewrote the SOAP request handler. It now uses a sax parser rather than dom, which is also faster and less memory consuming.

After releasing 0.6.2 I found that there was one last glitch: handling lists of primitives, unfortunately that is exactly what your add_many method taks as argument, so that won't work with 0.6.2. That being said I have of course fixed this issue on the trunk of Ladon's sourcetree, so you should be able to get both your methods working if you install from source: http://ladonize.org/index.php/Python_install#Bleeding_Edge , otherwise you can wait for version 0.6.3 :-)

Here is the result of your service running on trunk edition of Ladon with Suds as client:
http://pastebin.com/p9aqEnq3

NOTE: I'd like to mention aswell that your problems have been strictly related to the SOAP interface, JSON-WSP has been working all along.

jsgaarde (jakob-simon-gaarde) said : #15

Fix was commited