suds-community / suds

Suds is a lightweight SOAP python client for consuming Web Services. A community fork of the jurko fork.
https://suds.readthedocs.io/
GNU Lesser General Public License v3.0
172 stars 54 forks source link

Handling of xsd:anytype #54

Open oliver-sc opened 3 years ago

oliver-sc commented 3 years ago

Hi,

I am using suds to communicate with our Polarion Server to read/write Polarion Work Items (Work Item: Polarion object). The Work Item data structure contains a custom field which is of type "ArrayOfCustom". This array contains elements of type "Custom" as shown below:

<complexType name="Custom">
    <sequence>
        <element name="key" type="xsd:string"/>
        <element name="value" nillable="true"/>
    </sequence>
</complexType>
<complexType name="ArrayOfCustom">
    <sequence>
        <element maxOccurs="unbounded" minOccurs="0" name="Custom" type="tns3:Custom"/>
    </sequence>
</complexType>

For "Custom.value", no type is defined as it can be different for each custom field entry. This was no problem so far as the types used for "value" were strings or enums. Now, I added the custom field "lastTestRunDatetime" of type "xsd:dateTime". When I read the Work Item form the server, I get the following SOAP data transfer:

<ns3:customFields>
   <ns3:Custom>
      <ns3:key>lastTestRunString</ns3:key>
      <ns3:value xsi:type="xsd:string">2021-03-26 12:36</ns3:value>
   </ns3:Custom>
   <ns3:Custom>
      <ns3:key>lastTestRunDatetime</ns3:key>
      <ns3:value xsi:type="xsd:dateTime">2021-04-07T09:00:00.000Z</ns3:value>
   </ns3:Custom>
   <ns3:Custom>
      <ns3:key>lastTestResult</ns3:key>
      <ns3:value xsi:type="ns3:EnumOptionId">
         <ns3:id xsi:type="xsd:string">passed</ns3:id>
      </ns3:value>
   </ns3:Custom>
</ns3:customFields>

i.e. the value for "lastTestRunDatetime" is transfered in the "xsd:dateTime" format.

Sending the same data back to the server, results in following SOAP data transfer:

<ns0:customFields>
  <ns0:Custom>
    <ns0:key>lastTestRunString</ns0:key>
    <ns0:value>2021-03-26 12:36</ns0:value>
  </ns0:Custom>
  <ns0:Custom>
    <ns0:key>lastTestRunDatetime</ns0:key>
    <ns0:value>2021-04-07 09:00:00+00:00</ns0:value>
  </ns0:Custom>
  <ns0:Custom>
    <ns0:key>lastTestResult</ns0:key>
    <ns0:value><ns0:id>passed</ns0:id></ns0:value>
  </ns0:Custom>
</ns0:customFields>

i.e the value for "lastTestRunDatetime" changed from "2021-04-07T09:00:00.000Z" to "2021-04-07 09:00:00+00:00". which results in the server error "java.lang.NumberFormatException: Invalid date" (The " " instead of "T" is causing this error).

As this works for other fields that have the "xsd:dateTime" in the WSDL description, I did a bit of debugging: As value has no type specified in the WSDL description, the lastTestRunDatetime value is serialized via the regular Python data type "dateTime.dateTime" string conversion. For fields that are specified as "xsd:dateTime", the data type "suds.sax.date.Datetime" is used for the string conversion which calls .isoformat() to do the string conversion.

Is there a way to change this behavior at application level, e.g. by setting the type for value from "xsd:anyType" to "xsd:dateTime"?

If not, what would be the best way to patch the suds library? After a bit of debugging, I see the following possibility:

But this looks like a brute force approach. I would rather prefer to change the "type determination" when node "lastTestRunDatetime" is processed.

Any ideas how to solve this in a clean way without breaking other suds based applications?

Regards, Oliver

oliver-sc commented 3 years ago

Short update: I just tried this with zeep. It handles this without problem. It looks it has a more advanced "xsd:anyType" handling. Probably time to switch to zeep....