Source code for vmware.vapi.bindings.struct

"""
Bindings data classes
"""

__author__ = 'VMware, Inc.'
__copyright__ = 'Copyright (c) 2015 VMware, Inc.  All rights reserved.'

import decimal
import six
import sys
try:
    import simplejson as json
except ImportError:
    import json

from vmware.vapi.bindings.common import raise_core_exception
from vmware.vapi.data.serializers import cleanjson


# TODO: Split this into static and dynamic structures.
[docs]class VapiStruct(object): """ Representation of IDL Structure in python language bindings """ _validator_list = None def __init__(self, mappings=None, struct_value=None): """ Initialize VapiStruct :type mappings: :class:`dict` or :class:`None` :param mappings: A mapping for all field names whose IDL name does not match PEP8 standard name :type struct_value: :class:`vmware.vapi.data.value.StructValue` :param struct_value: StructValue to be used for VapiStruct or :class:`None` """ self._mappings = mappings # fields will either be in native form or in unknown # fields self._unexpected_fields = None self._struct_value = struct_value
[docs] def get_field(self, attr): """ Returns the struct field value :type attr: :class:`str` :param attr: Field name as defined in IDL :rtype: :class:`object` :return: Field value """ if self._mappings and attr in self._mappings: return getattr(self, self._mappings[attr]) else: return getattr(self, attr)
@classmethod
[docs] def validate_struct_value(cls, struct_value): """ Validate if the given struct value satisfies all the constraints of this VapiStruct. :type struct_value: :class:`vmware.vapi.data.value.StructValue` :param struct_value: StructValue to be validated :type validators: :class:`list` of :class:`vmware.vapi.data.validator.Validator` :param validators: List of validators :raise :class:`vmware.vapi.exception.CoreException` if a constraint is not satisfied """ if cls._validator_list: for validator in cls._validator_list: msg_list = validator.validate(struct_value, None) raise_core_exception(msg_list)
[docs] def validate_constraints(self): """ Validate if the current VapiStruct instance satisfies all the constraints of this VapiStruct type. :raise :class:`vmware.vapi.exception.CoreException` if a constraint is not satisfied """ struct_value = self.get_struct_value() self.validate_struct_value(struct_value)
@classmethod
[docs] def get_binding_type(cls): """ Returns the corresponding BindingType for the VapiStruct class :rtype: :class:`vmware.vapi.bindings.type.BindingType` :return: BindingType for this VapiStruct """ return getattr(cls, '_binding_type', None)
@classmethod def _set_binding_type(cls, binding_type): """ Set the underlying BindingType for this VapiStruct. :type binding_type: :class:`vmware.vapi.bindings.type.BindingType` :param binding_type: BindingType for this VapiStruct """ cls._binding_type = binding_type
[docs] def get_struct_value(self): """ Returns the corresponding StructValue for the VapiStruct class :rtype: :class:`vmware.vapi.data.value.StructValue` :return: StructValue for this VapiStruct """ # For dynamic structures if self._struct_value: return self._struct_value else: # For static structures from vmware.vapi.bindings.converter import TypeConverter struct_value = TypeConverter.convert_to_vapi(self, self._binding_type) unexpected_fields = self._unexpected_fields or {} for k, v in six.iteritems(unexpected_fields): struct_value.set_field(k, v) return struct_value
def _set_unexpected_fields(self, unexpected_fields=None): """ Set the underlying StructValue for this VapiStruct. This is an internal method and should only be used by vAPI runtime. :type unexpected_fields: :class:`dict` of :class:`str` and :class:`vmware.vapi.data.value.DataValue` or :class:`None` :param struct_value: StructValue for this VapiStruct """ self._unexpected_fields = unexpected_fields
[docs] def convert_to(self, cls): """ Convert the underlying StructValue to an instance of the provided class if possible. Conversion will be possible if the StructValue contains all the fields expected by the provided class and the type of the value in each fields matches the type of the field expected by the provided class. :type cls: :class:`vmware.vapi.data.value.StructValue` :param cls: The type to convert to :rtype: :class:'vmware.vapi.bindings.struct.VapiStruct' :return: The converted value """ from vmware.vapi.bindings.converter import TypeConverter return TypeConverter.convert_to_python(self.get_struct_value(), cls.get_binding_type())
[docs] def to_json(self): """ Convert the object into a json string. :rtype: :class:`str` :return: JSON string representation of this object """ struct_value = self.get_struct_value() return cleanjson.DataValueConverter.convert_to_json(struct_value)
[docs] def to_dict(self): """ Convert the object into a python dictionary. Even the nested types are converted to dictionaries. :rtype: :class:`dict` :return: Dictionary representation of this object """ # TODO: Implement native converter from DataValue -> Dictionary # to improve performance if it is used heavily return json.loads(self.to_json(), parse_float=decimal.Decimal)
def _get_attrs(self): """ Returns the attributes of the vAPI structure object :rtype: :class:`list` of :class:`str` :return: List of attributes of this object """ # Using getmembers in inspect to return all the attributes # of this object. And later filter those to get only the # public data attributes return [k for k in six.iterkeys(vars(self)) if not k.startswith('_')] def __eq__(self, other): if other is None: return False for attr in self._get_attrs(): if getattr(self, attr) != getattr(other, attr): return False return True def __ne__(self, other): return not (self == other) def __repr__(self): class_name = self.__class__.__name__ attrs = self._get_attrs() result = ', '.join( ['%s=%s' % (attr, repr(getattr(self, attr))) for attr in attrs]) return '%s(%s)' % (class_name, result) def __str__(self): attrs = self._get_attrs() result = ', '.join( ['%s : %s' % (attr, str(getattr(self, attr))) for attr in attrs]) return '{%s}' % result def __hash__(self): return str(self).__hash__()
[docs]class PrettyPrinter(object): """ Helper class to pretty print Python native values (with special support for VapiStruct objects). """ def __init__(self, stream=sys.stdout, indent=2): """ Initialize PrettyPrinter :type stream: :class:`object` :param stream: A stream object that implements File protocol's write operation :type indent: :class:`int` :param indent: Indentation to be used for new lines """ self._stream = stream self._indent = indent
[docs] def pprint(self, value, level=0): """ Print a Python native value :type value: :class:`vmware.vapi.bindings.struct.VapiStruct` :param value: VapiStruct to be pretty printed :type level: :class:`int` :param level: Indentation level """ self._process_value(value, level)
def _print_level(self, value, level, newline=True): """ Print data at a given identation level :type value: :class:`str` :param value: String to be printed :type level: :class:`int` :param level: Indentation level :type newline: :class:`bool` :param newline: If true, prints a new line after the data. If false, only prints the data """ if level: self._stream.write(' ' * level + value) else: self._stream.write(value) if newline: self._stream.write('\n') def _process_value(self, value, level=0): """ Process a value :type value: :class:`object` :param value: Value to be processed :type level: :class:`int` :param level: Indentation level """ if isinstance(value, VapiStruct): self._pprint_struct(value, level + self._indent) elif isinstance(value, dict): self._pprint_dict(value, level + self._indent) elif isinstance(value, list): self._pprint_list(value, level + self._indent) elif isinstance(value, six.string_types): self._print_level("'%s'," % value, 0) elif isinstance(value, six.integer_types): self._print_level('%s,' % value, 0) elif value is None: self._print_level('None,', 0) else: self._print_level('%s,' % value, level) def _pprint_struct(self, value, level=0): """ Pretty print a struct :type value: :class:`vmware.vapi.bindings.struct.VapiStruct` :param value: Value to be processed :type level: :class:`int` :param level: Indentation level """ class_name = value.__class__.__name__ self._print_level(class_name + '(', 0) for k in sorted(value._get_attrs()): # pylint: disable=W0212 v = getattr(value, k) self._print_level('%s=' % k, level, False) self._process_value(v, level) self._print_level('),', level - self._indent) def _pprint_dict(self, value, level=0): """ Pretty print a dictionary :type value: :class:`dict` :param value: Value to be processed :type level: :class:`int` :param level: Indentation level """ if not value: self._print_level('{},', 0) return self._print_level('{', 0) for k in sorted(value.keys()): self._print_level("'%s':" % k, level, False) self._process_value(value[k], level) self._print_level('},', level - self._indent) def _pprint_list(self, value, level=0): """ Pretty print a list :type value: :class:`list` :param value: Value to be processed :type level: :class:`int` :param level: Indentation level """ if not value: self._print_level('[],', 0) return self._print_level('[', 0) for v in value: self._print_level('', level, False) self._process_value(v, level) self._print_level('],', level - self._indent)