nickesk / pyactiveresource

Automatically exported from code.google.com/p/pyactiveresource
Other
0 stars 0 forks source link

pyactiveresource does not handle nested attributes correctly #5

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
When using pyactiveresource with the slicehost API, it incorrectly handles
nested elements in the response text. 

For example, a response from api.slicehost.com/slices.xml:

  <slice>
    <name>cloudkick0</name>
    <status>active</status>
    <addresses type="array">
      <address>173.45.XXX.XXX</address>

      <address>172.21.XXX.XXX</address>
    </addresses>
    <id type="integer">ZZZZZ</id>
    <progress type="integer">100</progress>
    <bw-out type="float">0.69</bw-out>
    <bw-in type="float">0.62</bw-in>

    <image-id type="integer">11</image-id>
    <ip-address>173.45.XXX.XXX</ip-address>
    <flavor-id type="integer">4</flavor-id>
  </slice>

Calling to_xml() on this Slice object returns:

<slice>
  <status>active</status>
  <name>cloudkick0</name>
  <bw-in>0.62</bw-in>
  <bw-out>0.69</bw-out>
  <image-id type="integer">11</image-id>
  <flavor-id type="integer">4</flavor-id>
  <progress type="integer">100</progress>
  <ip-address>173.45.XXX.XXX</ip-address>
  <id type="integer">ZZZZZ</id>
  <addresses type="array">
    <address />
    <address />
  </addresses>
</slice>

You'll notice the address elements are no longer there.

Applying this patch sort of makes it work:

--- activeresource.py.old   2009-02-24 11:32:18.000000000 -0800
+++ activeresource.py   2009-02-24 11:32:20.000000000 -0800
@@ -858,7 +858,7 @@
                 attr = klass(value)
             elif isinstance(value, list):
                 klass = self._find_class_for(util.singularize(key))
-                attr = [klass(child) for child in value]
+                attr = [klass({'value': child}) for child in value]
             else:
                 attr = value
             # Store the actual value in the attributes dictionary

Now the result is:

<slice>
  <status>active</status>
  <name>cloudkick0</name>
  <bw-in>0.62</bw-in>
  <bw-out>0.69</bw-out>
  <image-id type="integer">11</image-id>
  <flavor-id type="integer">4</flavor-id>
  <progress type="integer">100</progress>
  <ip-address>173.45.XXX.XXX</ip-address>
  <id type="integer">ZZZZZ</id>
  <addresses type="array">
    <address>
      <value>173.45.XXX.XXX</value>
    </address>
    <address>
      <value>172.21.XXX.XXX</value>
    </address>
  </addresses>
</slice>

This is still incorrect, but at least we can access that data. Any ideas of
a proper fix?

Thanks!

Original issue reported on code.google.com by alexpo...@gmail.com on 24 Feb 2009 at 7:34

GoogleCodeExporter commented 9 years ago
Hi, Alex. Sorry to have missed this report. I need to make these things go to 
the
mailing list.

Hm, that's an interesting one. I think slicehost might be using an older 
version of
rails because Ruby's ActiveResource 2 doesn't like that xml either:

>> s.attributes
=> {"name"=>"cloudkick0", "status"=>"active", "addresses"=>["173.45.XXX.XXX",
"172.21.XXX.XXX"], "id"=>0, "progress"=>100, "bw_out"=>0.69, "bw_in"=>0.62,
"image_id"=>11, "ip_address"=>"173.45.XXX.XXX", "flavor_id"=>4}
>> s.to_xml
RuntimeError: Not all elements respond to to_xml

A solution I have used to handle older servers is to subclass the Connection 
class
with one that does horrible regex hacks on the xml before/after 
encoding/decoding.

Original comment by mark.r.r...@gmail.com on 4 Apr 2009 at 3:57

GoogleCodeExporter commented 9 years ago
I'm running into this exact same problem, was there any proper fix yet or 
should I just use the workaround 
above?

/Oli

Original comment by osvalds...@gmail.com on 17 Nov 2009 at 10:15

GoogleCodeExporter commented 9 years ago
The workaround above isn't exactly "correct" as it adds a "value" element to the
array, which is not the behavior of Ruby ARes, which preserves the array format.

>> class Slice < ActiveResource::Base
>>  self.site = 'http://localhost:3000'
>> end

>> xml = '''...'''
>> site = Site.new(Hash.from_xml(xml)['site'])
>> site.addresses
=> ["173.45.XXX.XXX", "172.21.XXX.XXX"]

However as Mark mentions, to_xml blows up on the address Array

>> site.to_xml
RuntimeError: Not all elements respond to to_xml
...

So this is a problem with the server's XML not being ARes-compliant. PyARes is 
a port
of the Ruby implementation, so this should be reported upstream if you feel 
this is
really a bug.

Original comment by nick...@gmail.com on 17 Nov 2009 at 4:45

GoogleCodeExporter commented 9 years ago
Of course that should be "Slice.new(Hash.from_xml(xml)['slice'])" above

Original comment by nick...@gmail.com on 17 Nov 2009 at 4:49