diff --git a/reddwarfclient/xml.py b/reddwarfclient/xml.py
index ee064099..82a83457 100644
--- a/reddwarfclient/xml.py
+++ b/reddwarfclient/xml.py
@@ -5,23 +5,52 @@ from numbers import Number
from reddwarfclient import exceptions
from reddwarfclient.client import ReddwarfHTTPClient
-
XML_NS = {None: "http://docs.openstack.org/database/api/v1.0"}
-# This dictionary contains XML paths of things that should become list items.
+# If XML element is listed here then this searches through the ancestors.
LISTIFY = {
"accounts": [[]],
"databases": [[]],
"flavors": [[]],
"instances": [[]],
- "links": [["flavor", "instance", "instances"],
- ["instance", "instances"]],
+ "links": [[]],
"hosts": [[]],
"devices": [[]],
"users": [[]],
"versions": [[]],
+ "attachments": [[]]
}
+TYPE_MAP = {
+ "instance": {
+ "volume": {
+ "used": float,
+ "size": int,
+ },
+ "deleted": bool,
+ "server": {
+ "local_id": int,
+ "deleted": bool,
+ },
+ },
+ "instances": {
+ "deleted": bool,
+ },
+ "deleted": bool,
+ "flavor": {
+ "ram": int,
+ },
+ "diagnostics": {
+ "vmHwm": int,
+ "vmPeak": int,
+ "vmSize": int,
+ "threads": int,
+ "vmRss": int,
+ "fdSize": int,
+ },
+}
+TYPE_MAP["flavors"] = TYPE_MAP["flavor"]
+
REQUEST_AS_LIST = set(['databases', 'users'])
@@ -60,8 +89,11 @@ def element_to_json(name, element):
def root_element_to_json(name, element):
"""Returns a tuple of the root JSON value, plus the links if found."""
if name == "rootEnabled": # Why oh why were we inconsistent here? :'(
- return bool(element.text), None
- elif element_must_be_list(element, name):
+ if element.text.strip() == "False":
+ return False, None
+ elif element.text.strip() == "True":
+ return True, None
+ if element_must_be_list(element, name):
return element_to_list(element, True)
else:
return element_to_dict(element), None
@@ -93,6 +125,12 @@ def element_to_dict(element):
for child_element in element:
name = normalize_tag(child_element)
result[name] = element_to_json(name, child_element)
+ if len(result) == 0 and element.text:
+ string_value = element.text.strip()
+ if len(string_value):
+ if string_value == 'None':
+ return None
+ return string_value
return result
@@ -177,10 +215,36 @@ def populate_element_from_dict(element, dict):
element.set(key, value)
elif isinstance(value, Number):
element.set(key, str(value))
+ elif isinstance(value, None.__class__):
+ element.set(key, '')
else:
create_subelement(element, key, value)
+def modify_response_types(value, type_translator):
+ """
+ This will convert some string in response dictionary to ints or bool
+ so that our respose is compatiable with code expecting JSON style responses
+ """
+ if isinstance(value, str):
+ if value == 'True':
+ return True
+ elif value == 'False':
+ return False
+ else:
+ return type_translator(value)
+ elif isinstance(value, dict):
+ for k, v in value.iteritems():
+ if v.__class__ is dict and v.__len__() == 0:
+ value[k] = None
+ if k in type_translator:
+ value[k] = modify_response_types(value[k], type_translator[k])
+ return value
+ elif isinstance(value, list):
+ return [modify_response_types(element, type_translator)
+ for element in value]
+
+
class ReddwarfXmlClient(ReddwarfHTTPClient):
@classmethod
@@ -208,4 +272,5 @@ class ReddwarfXmlClient(ReddwarfHTTPClient):
result = {root_name: root_value}
if links:
result['links'] = links
+ modify_response_types(result, TYPE_MAP)
return result
diff --git a/tests/test_xml.py b/tests/test_xml.py
index 4c20784d..cda382be 100644
--- a/tests/test_xml.py
+++ b/tests/test_xml.py
@@ -37,6 +37,20 @@ class XmlTest(TestCase):
['instances',
'instance']))
+ def test_populate_element_from_dict(self):
+ # Test populate_element_from_dict with a None in the data
+ ele = '''
+
+
+
+
+
+ '''
+ rt = etree.fromstring(ele)
+
+ self.assertEqual(None, xml.populate_element_from_dict(rt,
+ {'size': None}))
+
def test_element_must_be_list(self):
# Test for when name isn't in the dictionary
self.assertFalse(xml.element_must_be_list(self.ROOT, "not_in_list"))
@@ -66,9 +80,15 @@ class XmlTest(TestCase):
self.assertEqual((exp, None),
xml.root_element_to_json("not_in_list", self.ROOT))
- # Test rootEnabled:
+ # Test rootEnabled True:
+ t_element = etree.fromstring(''' True ''')
self.assertEqual((True, None),
- xml.root_element_to_json("rootEnabled", self.ROOT))
+ xml.root_element_to_json("rootEnabled", t_element))
+
+ # Test rootEnabled False:
+ f_element = etree.fromstring(''' False ''')
+ self.assertEqual((False, None),
+ xml.root_element_to_json("rootEnabled", f_element))
def test_element_to_list(self):
# Test w/ no child elements
@@ -89,9 +109,19 @@ class XmlTest(TestCase):
check_for_links=True))
def test_element_to_dict(self):
+ # Test when there is not a None
exp = {'instance': {'flavor': {'links': [], 'value': {'value': '5'}}}}
self.assertEqual(exp, xml.element_to_dict(self.ROOT))
+ # Test when there is a None
+ element = '''
+
+ None
+
+ '''
+ rt = etree.fromstring(element)
+ self.assertEqual(None, xml.element_to_dict(rt))
+
def test_standarize_json(self):
xml.standardize_json_lists(self.JSON)
self.assertEqual({'instances': ['1', '2', '3'],
@@ -154,6 +184,27 @@ class XmlTest(TestCase):
except TypeError:
pass
+ def test_modify_response_types(self):
+ TYPE_MAP = {
+ "Int": int,
+ "Bool": bool
+ }
+ #Is a string True
+ self.assertEqual(True, xml.modify_response_types('True', TYPE_MAP))
+
+ #Is a string False
+ self.assertEqual(False, xml.modify_response_types('False', TYPE_MAP))
+
+ #Is a dict
+ test_dict = {"Int": "5"}
+ test_dict = xml.modify_response_types(test_dict, TYPE_MAP)
+ self.assertEqual(int, test_dict["Int"].__class__)
+
+ #Is a list
+ test_list = {"a_list": [{"Int": "5"}, {"Str": "A"}]}
+ test_list = xml.modify_response_types(test_list["a_list"], TYPE_MAP)
+ self.assertEqual([{'Int': 5}, {'Str': 'A'}], test_list)
+
def test_reddwarfxmlclient(self):
from reddwarfclient import exceptions