Parse attributes according to their types
Follow OCCI 1.2 text rendering to parse attributes as string, number, boolean or enum. Change-Id: I7b78509a276abc6d77e72598f5da234be2e72a00
This commit is contained in:
parent
32ef451892
commit
1df2897254
|
@ -212,7 +212,8 @@ def create_header_occi(params, category, project=None):
|
|||
att = ""
|
||||
if params is not None:
|
||||
for k, v in params.items():
|
||||
att = "%s, %s=%s" % (att, k, v)
|
||||
# FIXME(enolfc): this assumes all attributes are strings
|
||||
att = "%s, %s=\"%s\"" % (att, k, v)
|
||||
headers["X_OCCI_Attribute"] = att
|
||||
if category is not None:
|
||||
cat = ""
|
||||
|
|
|
@ -147,8 +147,8 @@ class TestNetNeutronController(test_middleware.TestMiddleware):
|
|||
'"http://schemas.ogf.org/occi/infrastructure/'
|
||||
'network#";'
|
||||
'class="mixin",',
|
||||
'X-OCCI-Attribute': '"occi.core.title"="%s",'
|
||||
'"occi.network.address"="%s"' %
|
||||
'X-OCCI-Attribute': 'occi.core.title="%s",'
|
||||
'occi.network.address="%s"' %
|
||||
(name, address)
|
||||
}
|
||||
req = self._build_req(path="/network",
|
||||
|
@ -295,8 +295,8 @@ class TestNetNovaController(test_middleware.TestMiddleware):
|
|||
'"http://schemas.ogf.org/occi/'
|
||||
'infrastructure/network#";'
|
||||
'class="mixin",',
|
||||
'X-OCCI-Attribute': '"occi.core.title"="%s",'
|
||||
'"occi.network.address"="%s"' %
|
||||
'X-OCCI-Attribute': 'occi.core.title="%s",'
|
||||
'occi.network.address="%s"' %
|
||||
(name, address)
|
||||
}
|
||||
req = self._build_req(path="/network",
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
# under the License.
|
||||
|
||||
import collections
|
||||
import numbers
|
||||
|
||||
|
||||
from ooi import exception
|
||||
|
@ -60,13 +61,15 @@ class BaseParserTest(object):
|
|||
self.assertEqual({}, res["attributes"])
|
||||
|
||||
def test_attributes(self):
|
||||
expected_attrs = {"foo": "bar", "baz": 1234, "bazonk": "foo=123",
|
||||
"boolt": True, "enum": "whatev", "boolf": False,
|
||||
"float": 3.14}
|
||||
h, b = self.get_test_attributes(
|
||||
{"term": "foo", "scheme": "http://example.com/scheme#"},
|
||||
[("foo", '"bar"'), ("baz", 1234), ("bazonk", '"foo=123"')]
|
||||
expected_attrs
|
||||
)
|
||||
parser = self._get_parser(h, b)
|
||||
res = parser.parse()
|
||||
expected_attrs = {"foo": "bar", "baz": "1234", "bazonk": "foo=123"}
|
||||
self.assertEqual(expected_attrs, res["attributes"])
|
||||
|
||||
def test_link(self):
|
||||
|
@ -74,12 +77,12 @@ class BaseParserTest(object):
|
|||
{"term": "foo", "scheme": "http://example.com/scheme#"},
|
||||
{
|
||||
"id": "bar",
|
||||
"attributes": [("foo", "bar"), ("bazonk", '"foo=123"')]
|
||||
"attributes": {"foo": 1234, "bazonk": "foo=123"}
|
||||
}
|
||||
)
|
||||
parser = self._get_parser(h, b)
|
||||
res = parser.parse()
|
||||
expected_links = {"bar": {"foo": "bar", "bazonk": "foo=123"}}
|
||||
expected_links = {"bar": {"foo": 1234, "bazonk": "foo=123"}}
|
||||
self.assertEqual(expected_links, res["links"])
|
||||
|
||||
|
||||
|
@ -103,17 +106,27 @@ class TestHeaderParser(BaseParserTest, base.TestCase):
|
|||
h["Category"] = ",".join(c)
|
||||
return h, b
|
||||
|
||||
def _get_attribute_value(self, value):
|
||||
if isinstance(value, bool):
|
||||
return '"%s"' % str(value).lower()
|
||||
elif isinstance(value, numbers.Number):
|
||||
return "%s" % value
|
||||
else:
|
||||
return '"%s"' % value
|
||||
|
||||
def get_test_attributes(self, kind, attributes):
|
||||
h, b = self.get_test_kind(kind)
|
||||
attrs = ["%s=%s" % (a[0], a[1]) for a in attributes]
|
||||
attrs = []
|
||||
for n, v in attributes.items():
|
||||
attrs.append("%s=%s" % (n, self._get_attribute_value(v)))
|
||||
h["X-OCCI-Attribute"] = ", ".join(attrs)
|
||||
return h, b
|
||||
|
||||
def get_test_link(self, kind, link):
|
||||
h, b = self.get_test_kind(kind)
|
||||
l = ["<%(id)s>" % link]
|
||||
for a in link["attributes"]:
|
||||
l.append('"%s"=%s' % (a[0], a[1]))
|
||||
for n, v in link["attributes"].items():
|
||||
l.append('"%s"=%s' % (n, self._get_attribute_value(v)))
|
||||
h["Link"] = "; ".join(l)
|
||||
return h, b
|
||||
|
||||
|
|
|
@ -108,13 +108,36 @@ class TextParser(BaseParser):
|
|||
"schemes": schemes,
|
||||
}
|
||||
|
||||
def parse_attribute_value(self, value):
|
||||
v = value.strip()
|
||||
# quoted: string or bool
|
||||
if v[0] == '"':
|
||||
v = v.strip('"')
|
||||
if v == "true":
|
||||
return True
|
||||
elif v == "false":
|
||||
return False
|
||||
else:
|
||||
return v
|
||||
# unquoted: number or enum-val
|
||||
try:
|
||||
return int(v)
|
||||
except ValueError:
|
||||
try:
|
||||
return float(v)
|
||||
except ValueError:
|
||||
return v
|
||||
|
||||
def parse_attributes(self, headers):
|
||||
attrs = {}
|
||||
try:
|
||||
header_attrs = headers["X-OCCI-Attribute"]
|
||||
for attr in _quoted_split(header_attrs):
|
||||
l = _split_unquote(attr)
|
||||
attrs[l[0].strip()] = l[1]
|
||||
try:
|
||||
n, v = attr.split("=", 1)
|
||||
attrs[n.strip()] = self.parse_attribute_value(v)
|
||||
except ValueError:
|
||||
raise exception.OCCIInvalidSchema("Unable to parse")
|
||||
except KeyError:
|
||||
pass
|
||||
return attrs
|
||||
|
@ -131,8 +154,11 @@ class TextParser(BaseParser):
|
|||
if ll[0][1] != "<" and ll[0][-1] != ">":
|
||||
raise exception.OCCIInvalidSchema("Unable to parse link")
|
||||
link_dest = ll[0][1:-1]
|
||||
d = {}
|
||||
try:
|
||||
d = dict([_split_unquote(i) for i in ll[1:]])
|
||||
for attr in ll[1:]:
|
||||
n, v = attr.split("=", 1)
|
||||
d[n.strip().strip('"')] = self.parse_attribute_value(v)
|
||||
except ValueError:
|
||||
raise exception.OCCIInvalidSchema("Unable to parse link")
|
||||
links[link_dest] = d
|
||||
|
|
Loading…
Reference in New Issue