deb-murano/muranoapi/dsl/murano_object.py
Stan Lagun c4266d89df Rename Type to Usage for MuranoPL properties
Change-Id: Ide9368fd57d3322476d59c7d4cbb83d59736f664
Closes-Bug: #1308924
2014-04-20 23:06:49 +04:00

192 lines
6.9 KiB
Python

# Copyright (c) 2014 Mirantis, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import types
import yaml
import yaql.context
import muranoapi.dsl.exceptions as exceptions
import muranoapi.dsl.helpers
import muranoapi.dsl.type_scheme as type_scheme
import muranoapi.dsl.typespec as typespec
class MuranoObject(object):
def __init__(self, murano_class, parent_obj, object_store, context,
object_id=None, known_classes=None, defaults=None):
if known_classes is None:
known_classes = {}
self.__parent_obj = parent_obj
self.__object_id = object_id or muranoapi.dsl.helpers.generate_id()
self.__type = murano_class
self.__properties = {}
self.__object_store = object_store
self.__parents = {}
self.__context = context
self.__defaults = defaults or {}
known_classes[murano_class.name] = self
for parent_class in murano_class.parents:
name = parent_class.name
if name not in known_classes:
obj = parent_class.new(parent_obj, object_store, context,
None, object_id=self.__object_id,
known_classes=known_classes,
defaults=defaults)
self.__parents[name] = known_classes[name] = obj
else:
self.__parents[name] = known_classes[name]
def initialize(self, **kwargs):
used_names = set()
for i in xrange(2):
for property_name in self.__type.properties:
spec = self.__type.get_property(property_name)
needs_evaluation = muranoapi.dsl.helpers.needs_evaluation
if i == 0 and needs_evaluation(spec.default) or i == 1\
and property_name in used_names:
continue
used_names.add(property_name)
property_value = kwargs.get(property_name, type_scheme.NoValue)
self.set_property(property_name, property_value)
for parent in self.__parents.values():
parent.initialize(**kwargs)
@property
def object_id(self):
return self.__object_id
@property
def type(self):
return self.__type
@property
def parent(self):
return self.__parent_obj
def __getattr__(self, item):
if item.startswith('__'):
raise AttributeError('Access to internal attributes is '
'restricted')
return self.get_property(item)
def get_property(self, item, caller_class=None):
try:
return self.__get_property(item, caller_class)
except AttributeError:
if not caller_class:
raise AttributeError(item)
try:
obj = self.cast(caller_class)
return obj.__properties[item]
except KeyError:
raise AttributeError(item)
except TypeError:
raise AttributeError(item)
def __get_property(self, item, caller_class=None):
if item in self.__properties:
return self.__properties[item]
i = 0
result = None
for parent in self.__parents.values():
try:
result = parent.__get_property(item, caller_class)
i += 1
if i > 1:
raise LookupError()
except AttributeError:
continue
if not i:
raise AttributeError()
return result
def set_property(self, key, value, caller_class=None):
try:
self.__set_property(key, value, caller_class)
except AttributeError as e:
if not caller_class:
raise e
try:
obj = self.cast(caller_class)
obj.__properties[key] = value
except TypeError:
raise AttributeError(key)
def __set_property(self, key, value, caller_class=None):
if key in self.__type.properties:
spec = self.__type.get_property(key)
if caller_class is not None \
and (spec.usage not in typespec.PropertyUsages.Writable
or not caller_class.is_compatible(self)):
raise exceptions.NoWriteAccess(key)
default = self.__defaults.get(key, spec.default)
child_context = yaql.context.Context(parent_context=self.__context)
child_context.set_data(self)
default = muranoapi.dsl.helpers.evaluate(default, child_context, 1)
self.__properties[key] = spec.validate(
value, self, self.__context, self.__object_store, default)
else:
for parent in self.__parents.values():
try:
parent.__set_property(key, value, caller_class)
return
except AttributeError:
continue
raise AttributeError(key)
def cast(self, type):
if self.type == type:
return self
for parent in self.__parents.values():
try:
return parent.cast(type)
except TypeError:
continue
raise TypeError('Cannot cast')
def __repr__(self):
return yaml.safe_dump(muranoapi.dsl.helpers.serialize(self))
def to_dictionary(self, include_hidden=False):
result = {}
for parent in self.__parents.values():
result.update(parent.to_dictionary(include_hidden))
result.update({'?': {'type': self.type.name, 'id': self.object_id}})
if include_hidden:
result.update(self.__properties)
else:
for property_name in self.type.properties:
if property_name in self.__properties:
spec = self.type.get_property(property_name)
if spec.usage != typespec.PropertyUsages.Runtime:
result[property_name] = \
self.__properties[property_name]
return result
def __merge_default(self, src, defaults):
if src is None:
return
if type(src) != type(defaults):
raise ValueError()
if isinstance(defaults, types.DictionaryType):
for key, value in defaults.iteritems():
src_value = src.get(key)
if src_value is None:
continue