#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright © 2014-2016 NetApp, Inc. All Rights Reserved.
#
# CONFIDENTIALITY NOTICE: THIS SOFTWARE CONTAINS CONFIDENTIAL INFORMATION OF
# NETAPP, INC. USE, DISCLOSURE OR REPRODUCTION IS PROHIBITED WITHOUT THE PRIOR
# EXPRESS WRITTEN PERMISSION OF NETAPP, INC.
from __future__ import unicode_literals
import json
from uuid import UUID
from future.utils import with_metaclass
VER3 = False
try:
unicode
except:
VER3 = True
KNOWN_CONVERSIONS = {
type(set): list,
UUID: str
}
def _as_ascii(val):
"""
Helper method for enforcing ascii encoding.
:param val: any string, basestring, or unicode string
:type val: basestring
:return: a string
"""
return str(val.encode('ascii', 'ignore'))
[docs]def serialize(val):
"""
DataObject serializer value based on MetaData attributes.
:param val: any value
:return: the serialized value
"""
if hasattr(val, 'custom_to_json'):
return_value = val.custom_to_json()
elif hasattr(val, 'to_json'):
return_value = val.to_json()
elif type(val) in KNOWN_CONVERSIONS:
return_value = KNOWN_CONVERSIONS[type(val)](val)
elif isinstance(val, dict):
return_value = dict((k, serialize(v)) for k, v in val.items())
elif isinstance(val, list):
return_value = list(serialize(v) for v in val)
elif hasattr(val, '_optional') and val.optional():
return_value = None
else:
return_value = val
return return_value
[docs]class ModelProperty(object):
"""
ModelProperty metadata container for API data type information.
"""
def __init__(self, member_name, member_type, array=False, optional=False,
documentation=None, dictionaryType = None):
"""
ModelProperty constructor.
:param member_name: the name of the property.
:type member_name: str
:param member_type: the type of the property.
:type member_type: str
:param array: is the property an array.
:type array: bool
:param optional: is the property optional.
:type optional: bool
:param documentation: documentation for the property.
:type documentation: str
"""
self._member_name = member_name
self._member_type = member_type
self._array = array
self._optional = optional
self._documentation = documentation
self._dictionaryType = dictionaryType
def __repr__(self):
if self._array:
arr = '[]'
else:
arr = ''
full_type = '{}'.format(self._member_type).replace('\'>', arr + '\'>')
return full_type
[docs] def extend_json(self, out, data):
"""
Serialize the property as json-like structure.
:param out: the resulting output.
:param data: the data to be converted.
"""
if data is None or hasattr(data, '_member_type'): # HACK ALERT
if not self._optional:
# We want to catch this error.
#raise ValueError(self._member_name+" is a required parameter.")
# THE OLD WAY!
out[self._member_name] = None
elif self._array:
out[self._member_name] = [serialize(x) for x in data]
elif self._optional:
optional_data = serialize(data)
if optional_data is not None:
out[self._member_name] = optional_data
else:
out[self._member_name] = serialize(data)
[docs] def member_name(self):
"""
:return: the member name.
"""
return self._member_name
[docs] def member_type(self):
"""
:return: the member type.
"""
return self._member_type
[docs] def array(self):
"""
:return: is the property an array
"""
return self._array
[docs] def optional(self):
"""
:return: is the property optional
"""
return self._optional
[docs] def documentation(self):
"""
:return: the property documentation
"""
return self._documentation
[docs] def known_default(self):
"""
Helps convert a property to a default value.
:return: a known default for a type.
"""
if self._member_type is int:
return 0
elif self._member_type is float:
return 0.0
elif self._member_type is str:
return ''
elif self._member_type is bool:
return False
else:
pass
[docs]class DataObject(with_metaclass(MetaDataObject, ModelProperty)):
"""
DataObject is the base type for all generated types, including the MetaData
properties, as described from the api descriptors.
"""
_properties = None
@classmethod
def _create_properties(cls):
"""
Maps api descriptor attributes to the MetaData properties for this
object.
"""
cls._properties = {}
for name in dir(cls):
prop = getattr(cls, name, None)
if isinstance(prop, ModelProperty):
cls._properties[name] = prop
def __init__(self, **kwargs):
# Iterate through available properties and start removing them
# from kwargs
for name, property in type(self)._properties.items():
if not property.optional() and name not in kwargs.keys() and name != "secret":
raise ValueError(name+" is a required parameter.")
if name in kwargs:
setattr(self, name, kwargs[name])
del kwargs[name]
if(len(kwargs.keys()) != 0):
raise ValueError("The following params are invalid: "+str(kwargs.keys()))
[docs] def get_properties(self):
"""
Exposes the type properties for a Data Object.
:return: the dictionary of property names and thier type information.
:rtype: dict
"""
return self._properties
def __repr__(self):
"""
Base repr() for all generated objects.
"""
props = []
member_items = self._properties
for name, prop in sorted(member_items.items()):
if prop.array() and hasattr(self, name):
try:
iter(getattr(self, name))
except TypeError:
attrs = []
else:
attrs = (repr(x) for x in getattr(self, name))
msg_fmt = '[{arr}]'
attr_repr = msg_fmt.format(
arr=str.join(str(', '), attrs))
else:
if hasattr(self, name):
attr_repr = getattr(self, name)
else:
attr_repr = None
msg_fmt = '{name}={repr!r}'
msg = msg_fmt.format(name=name, repr=attr_repr)
props.append(msg)
return str.format(str('{cls}({props})'),
cls=type(self).__name__,
props=str.join(str(', '), props))
[docs] def to_json(self):
"""
Converts DataObject to json.
:return: the DataObject as a json structure.
"""
out = {}
for name, prop in type(self)._properties.items():
prop.extend_json(out, getattr(self, name, None))
return out
[docs]def property(member_name, member_type,
array = False, optional = False,
documentation = None, dictionaryType = None):
"""
Constructs the type for a DataObject property.
:param member_name: the name of the property.
:type member_name: str
:param member_type: the type of the property.
:type member_type: type
:param array: is the property an array.
:type array: bool
:param optional: is the property optional.
:type optional: bool
:param documentation: documentation for the property.
:type documentation: str or NoneType
:return: the constructed type of a property
"""
msg_fmt = 'Property of type {typ}{arr}'
msg = msg_fmt.format(
typ=member_type,
arr='[]'
if array else ''
)
documentation = documentation or msg
typ = type(_as_ascii(member_name),
(ModelProperty,),
{
'__doc__': documentation,
})
return typ(member_name=member_name,
member_type=member_type,
array=array,
optional=optional,
documentation=documentation,
dictionaryType=dictionaryType)