summaryrefslogtreecommitdiff
path: root/neutronclient/common
diff options
context:
space:
mode:
authorElena Ezhova <eezhova@mirantis.com>2015-12-04 16:45:47 +0300
committerElena Ezhova <eezhova@mirantis.com>2015-12-09 11:09:26 +0300
commit54a4aea969fe06422f64005652ce23ac7b616d98 (patch)
tree4396ce48e37670e8c0f050c26fba7c7c2d6794f6 /neutronclient/common
parent88010add39f755ea4c2b4aa54ac6e66f48b1af51 (diff)
downloadpython-neutronclient-54a4aea969fe06422f64005652ce23ac7b616d98.tar.gz
Remove XML support
As XML support has been removed from neutron, there is no need to keep it in client. Dropped XML serializer and deserializer and deprecated "request-format" CLI option, making JSON the default and the only supported request format. DocImpact Change-Id: I88b0fdd65a649694252d5ff43a174e75026df5b1 Closes-Bug: #1380787
Diffstat (limited to 'neutronclient/common')
-rw-r--r--neutronclient/common/constants.py12
-rw-r--r--neutronclient/common/serializer.py287
2 files changed, 5 insertions, 294 deletions
diff --git a/neutronclient/common/constants.py b/neutronclient/common/constants.py
index 525a040..ccb22cd 100644
--- a/neutronclient/common/constants.py
+++ b/neutronclient/common/constants.py
@@ -14,18 +14,6 @@
# limitations under the License.
-EXT_NS = '_extension_ns'
-XML_NS_V20 = 'http://openstack.org/quantum/api/v2.0'
-XSI_NAMESPACE = "http://www.w3.org/2001/XMLSchema-instance"
-XSI_ATTR = "xsi:nil"
-XSI_NIL_ATTR = "xmlns:xsi"
-TYPE_XMLNS = "xmlns:quantum"
-TYPE_ATTR = "quantum:type"
-VIRTUAL_ROOT_KEY = "_v_root"
-ATOM_NAMESPACE = "http://www.w3.org/2005/Atom"
-ATOM_XMLNS = "xmlns:atom"
-ATOM_LINK_NOTATION = "{%s}link" % ATOM_NAMESPACE
-
TYPE_BOOL = "bool"
TYPE_INT = "int"
TYPE_LONG = "long"
diff --git a/neutronclient/common/serializer.py b/neutronclient/common/serializer.py
index f21e87c..e094c26 100644
--- a/neutronclient/common/serializer.py
+++ b/neutronclient/common/serializer.py
@@ -14,13 +14,10 @@
# under the License.
import logging
-from xml.etree import ElementTree as etree
-from xml.parsers import expat
from oslo_serialization import jsonutils
import six
-from neutronclient.common import constants
from neutronclient.common import exceptions as exception
from neutronclient.i18n import _
@@ -62,148 +59,6 @@ class JSONDictSerializer(DictSerializer):
return jsonutils.dumps(data, default=sanitizer)
-class XMLDictSerializer(DictSerializer):
-
- def __init__(self, metadata=None, xmlns=None):
- """XMLDictSerializer constructor.
-
- :param metadata: information needed to deserialize XML into
- a dictionary.
- :param xmlns: XML namespace to include with serialized XML
- """
- super(XMLDictSerializer, self).__init__()
- self.metadata = metadata or {}
- if not xmlns:
- xmlns = self.metadata.get('xmlns')
- if not xmlns:
- xmlns = constants.XML_NS_V20
- self.xmlns = xmlns
-
- def default(self, data):
- """Default serializer of XMLDictSerializer.
-
- :param data: expect data to contain a single key as XML root, or
- contain another '*_links' key as atom links. Other
- case will use 'VIRTUAL_ROOT_KEY' as XML root.
- """
- try:
- links = None
- has_atom = False
- if data is None:
- root_key = constants.VIRTUAL_ROOT_KEY
- root_value = None
- else:
- link_keys = [k for k in six.iterkeys(data) or []
- if k.endswith('_links')]
- if link_keys:
- links = data.pop(link_keys[0], None)
- has_atom = True
- root_key = (len(data) == 1 and
- list(data.keys())[0] or constants.VIRTUAL_ROOT_KEY)
- root_value = data.get(root_key, data)
- doc = etree.Element("_temp_root")
- used_prefixes = []
- self._to_xml_node(doc, self.metadata, root_key,
- root_value, used_prefixes)
- if links:
- self._create_link_nodes(list(doc)[0], links)
- return self.to_xml_string(list(doc)[0], used_prefixes, has_atom)
- except AttributeError as e:
- LOG.exception(str(e))
- return ''
-
- def __call__(self, data):
- # Provides a migration path to a cleaner WSGI layer, this
- # "default" stuff and extreme extensibility isn't being used
- # like originally intended
- return self.default(data)
-
- def to_xml_string(self, node, used_prefixes, has_atom=False):
- self._add_xmlns(node, used_prefixes, has_atom)
- return etree.tostring(node, encoding='UTF-8')
-
- # NOTE(ameade): the has_atom should be removed after all of the
- # XML serializers and view builders have been updated to the current
- # spec that required all responses include the xmlns:atom, the has_atom
- # flag is to prevent current tests from breaking
- def _add_xmlns(self, node, used_prefixes, has_atom=False):
- node.set('xmlns', self.xmlns)
- node.set(constants.TYPE_XMLNS, self.xmlns)
- if has_atom:
- node.set(constants.ATOM_XMLNS, constants.ATOM_NAMESPACE)
- node.set(constants.XSI_NIL_ATTR, constants.XSI_NAMESPACE)
- ext_ns = self.metadata.get(constants.EXT_NS, {})
- for prefix in used_prefixes:
- if prefix in ext_ns:
- node.set('xmlns:' + prefix, ext_ns[prefix])
-
- def _to_xml_node(self, parent, metadata, nodename, data, used_prefixes):
- """Recursive method to convert data members to XML nodes."""
- result = etree.SubElement(parent, nodename)
- if ":" in nodename:
- used_prefixes.append(nodename.split(":", 1)[0])
- # TODO(bcwaldon): accomplish this without a type-check
- if isinstance(data, list):
- if not data:
- result.set(
- constants.TYPE_ATTR,
- constants.TYPE_LIST)
- return result
- singular = metadata.get('plurals', {}).get(nodename, None)
- if singular is None:
- if nodename.endswith('s'):
- singular = nodename[:-1]
- else:
- singular = 'item'
- for item in data:
- self._to_xml_node(result, metadata, singular, item,
- used_prefixes)
- # TODO(bcwaldon): accomplish this without a type-check
- elif isinstance(data, dict):
- if not data:
- result.set(
- constants.TYPE_ATTR,
- constants.TYPE_DICT)
- return result
- attrs = metadata.get('attributes', {}).get(nodename, {})
- for k, v in sorted(data.items()):
- if k in attrs:
- result.set(k, str(v))
- else:
- self._to_xml_node(result, metadata, k, v,
- used_prefixes)
- elif data is None:
- result.set(constants.XSI_ATTR, 'true')
- else:
- if isinstance(data, bool):
- result.set(
- constants.TYPE_ATTR,
- constants.TYPE_BOOL)
- elif isinstance(data, int):
- result.set(
- constants.TYPE_ATTR,
- constants.TYPE_INT)
- elif isinstance(data, long):
- result.set(
- constants.TYPE_ATTR,
- constants.TYPE_LONG)
- elif isinstance(data, float):
- result.set(
- constants.TYPE_ATTR,
- constants.TYPE_FLOAT)
- LOG.debug("Data %(data)s type is %(type)s",
- {'data': data,
- 'type': type(data)})
- result.text = six.text_type(data)
- return result
-
- def _create_link_nodes(self, xml_doc, links):
- for link in links:
- link_node = etree.SubElement(xml_doc, 'atom:link')
- link_node.set('rel', link['rel'])
- link_node.set('href', link['href'])
-
-
class TextDeserializer(ActionDispatcher):
"""Default request body deserialization."""
@@ -227,140 +82,11 @@ class JSONDeserializer(TextDeserializer):
return {'body': self._from_json(datastring)}
-class XMLDeserializer(TextDeserializer):
-
- def __init__(self, metadata=None):
- """XMLDeserializer constructor.
-
- :param metadata: information needed to deserialize XML into
- a dictionary.
- """
- super(XMLDeserializer, self).__init__()
- self.metadata = metadata or {}
- xmlns = self.metadata.get('xmlns')
- if not xmlns:
- xmlns = constants.XML_NS_V20
- self.xmlns = xmlns
-
- def _get_key(self, tag):
- tags = tag.split("}", 1)
- if len(tags) == 2:
- ns = tags[0][1:]
- bare_tag = tags[1]
- ext_ns = self.metadata.get(constants.EXT_NS, {})
- if ns == self.xmlns:
- return bare_tag
- for prefix, _ns in ext_ns.items():
- if ns == _ns:
- return prefix + ":" + bare_tag
- else:
- return tag
-
- def _get_links(self, root_tag, node):
- link_nodes = node.findall(constants.ATOM_LINK_NOTATION)
- root_tag = self._get_key(node.tag)
- link_key = "%s_links" % root_tag
- link_list = []
- for link in link_nodes:
- link_list.append({'rel': link.get('rel'),
- 'href': link.get('href')})
- # Remove link node in order to avoid link node being
- # processed as an item in _from_xml_node
- node.remove(link)
- return link_list and {link_key: link_list} or {}
-
- def _from_xml(self, datastring):
- if datastring is None:
- return None
- plurals = set(self.metadata.get('plurals', {}))
- try:
- node = etree.fromstring(datastring)
- root_tag = self._get_key(node.tag)
- links = self._get_links(root_tag, node)
- result = self._from_xml_node(node, plurals)
- # There is no case where root_tag = constants.VIRTUAL_ROOT_KEY
- # and links is not None because of the way data are serialized
- if root_tag == constants.VIRTUAL_ROOT_KEY:
- return result
- return dict({root_tag: result}, **links)
- except Exception as e:
- parseError = False
- # Python2.7
- if (hasattr(etree, 'ParseError') and
- isinstance(e, getattr(etree, 'ParseError'))):
- parseError = True
- # Python2.6
- elif isinstance(e, expat.ExpatError):
- parseError = True
- if parseError:
- msg = _("Cannot understand XML")
- raise exception.MalformedResponseBody(reason=msg)
- else:
- raise
-
- def _from_xml_node(self, node, listnames):
- """Convert a minidom node to a simple Python type.
-
- :param node: minidom node name
- :param listnames: list of XML node names whose subnodes should
- be considered list items.
-
- """
- attrNil = node.get(str(etree.QName(constants.XSI_NAMESPACE, "nil")))
- attrType = node.get(str(etree.QName(
- self.metadata.get('xmlns'), "type")))
- if (attrNil and attrNil.lower() == 'true'):
- return None
- elif not len(node) and not node.text:
- if (attrType and attrType == constants.TYPE_DICT):
- return {}
- elif (attrType and attrType == constants.TYPE_LIST):
- return []
- else:
- return ''
- elif (len(node) == 0 and node.text):
- converters = {constants.TYPE_BOOL:
- lambda x: x.lower() == 'true',
- constants.TYPE_INT:
- lambda x: int(x),
- constants.TYPE_LONG:
- lambda x: long(x),
- constants.TYPE_FLOAT:
- lambda x: float(x)}
- if attrType and attrType in converters:
- return converters[attrType](node.text)
- else:
- return node.text
- elif self._get_key(node.tag) in listnames:
- return [self._from_xml_node(n, listnames) for n in node]
- else:
- result = dict()
- for attr in node.keys():
- if (attr == 'xmlns' or
- attr.startswith('xmlns:') or
- attr == constants.XSI_ATTR or
- attr == constants.TYPE_ATTR):
- continue
- result[self._get_key(attr)] = node.get(attr)
- children = list(node)
- for child in children:
- result[self._get_key(child.tag)] = self._from_xml_node(
- child, listnames)
- return result
-
- def default(self, datastring):
- return {'body': self._from_xml(datastring)}
-
- def __call__(self, datastring):
- # Adding a migration path to allow us to remove unncessary classes
- return self.default(datastring)
-
-
# NOTE(maru): this class is duplicated from neutron.wsgi
class Serializer(object):
"""Serializes and deserializes dictionaries to certain MIME types."""
- def __init__(self, metadata=None, default_xmlns=None):
+ def __init__(self, metadata=None):
"""Create a serializer based on the given WSGI environment.
'metadata' is an optional dict mapping MIME types to information
@@ -368,12 +94,10 @@ class Serializer(object):
"""
self.metadata = metadata or {}
- self.default_xmlns = default_xmlns
def _get_serialize_handler(self, content_type):
handlers = {
'application/json': JSONDictSerializer(),
- 'application/xml': XMLDictSerializer(self.metadata),
}
try:
@@ -381,22 +105,21 @@ class Serializer(object):
except Exception:
raise exception.InvalidContentType(content_type=content_type)
- def serialize(self, data, content_type):
+ def serialize(self, data):
"""Serialize a dictionary into the specified content type."""
- return self._get_serialize_handler(content_type).serialize(data)
+ return self._get_serialize_handler("application/json").serialize(data)
- def deserialize(self, datastring, content_type):
+ def deserialize(self, datastring):
"""Deserialize a string to a dictionary.
The string must be in the format of a supported MIME type.
"""
- return self.get_deserialize_handler(content_type).deserialize(
+ return self.get_deserialize_handler("application/json").deserialize(
datastring)
def get_deserialize_handler(self, content_type):
handlers = {
'application/json': JSONDeserializer(),
- 'application/xml': XMLDeserializer(self.metadata),
}
try: