61f84d03ca
The syntax is Try: - Throw: ns:name #can be list of names to simulate type hierarchy Message: message #optional Cause: $sourceException #optional Extra: { 'someExtra': 'data' } #optional Catch: - With: ns:name #can be list of names - As: exception #optional - Do: - Rethrow: Else: #optional - else block Finally: #optional - finally block Improves stack traces to contain information about Python native stack frames and macro blocks Change-Id: I2e2bcc5e1a0da5f9489d73525f8b3fa99cc0220c Implements: blueprint muranopl-exception-handling
122 lines
3.9 KiB
Python
122 lines
3.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 inspect
|
|
import types
|
|
|
|
import murano.dsl.macros as macros
|
|
import murano.dsl.typespec as typespec
|
|
import murano.dsl.virtual_exceptions as virtual_exceptions
|
|
import murano.dsl.yaql_expression as yaql_expression
|
|
|
|
try:
|
|
from collections import OrderedDict # noqa
|
|
except ImportError: # python2.6
|
|
from ordereddict import OrderedDict # noqa
|
|
|
|
|
|
macros.register()
|
|
virtual_exceptions.register()
|
|
|
|
|
|
class MethodUsages(object):
|
|
Action = 'Action'
|
|
Runtime = 'Runtime'
|
|
All = set([Action, Runtime])
|
|
|
|
|
|
def methodusage(usage):
|
|
def wrapper(method):
|
|
method._murano_method_usage = usage
|
|
return method
|
|
return wrapper
|
|
|
|
|
|
class MuranoMethod(object):
|
|
def __init__(self, namespace_resolver,
|
|
murano_class, name, payload):
|
|
self._name = name
|
|
self._namespace_resolver = namespace_resolver
|
|
|
|
if callable(payload):
|
|
self._body = payload
|
|
self._arguments_scheme = self._generate_arguments_scheme(payload)
|
|
self._usage = getattr(payload, '_murano_method_usage',
|
|
MethodUsages.Runtime)
|
|
else:
|
|
payload = payload or {}
|
|
self._body = self._prepare_body(payload.get('Body') or [], name)
|
|
self._usage = payload.get('Usage') or MethodUsages.Runtime
|
|
arguments_scheme = payload.get('Arguments') or []
|
|
if isinstance(arguments_scheme, types.DictionaryType):
|
|
arguments_scheme = [{key: value} for key, value in
|
|
arguments_scheme.iteritems()]
|
|
self._arguments_scheme = OrderedDict()
|
|
for record in arguments_scheme:
|
|
if not isinstance(record, types.DictionaryType) \
|
|
or len(record) > 1:
|
|
raise ValueError()
|
|
name = record.keys()[0]
|
|
self._arguments_scheme[name] = typespec.ArgumentSpec(
|
|
record[name], self._namespace_resolver)
|
|
|
|
self._murano_class = murano_class
|
|
|
|
@property
|
|
def name(self):
|
|
return self._name
|
|
|
|
@property
|
|
def murano_class(self):
|
|
return self._murano_class
|
|
|
|
@property
|
|
def arguments_scheme(self):
|
|
return self._arguments_scheme
|
|
|
|
@property
|
|
def usage(self):
|
|
return self._usage
|
|
|
|
@property
|
|
def body(self):
|
|
return self._body
|
|
|
|
def _generate_arguments_scheme(self, func):
|
|
func_info = inspect.getargspec(func)
|
|
data = [(name, {'Contract': yaql_expression.YaqlExpression('$')})
|
|
for name in func_info.args]
|
|
if inspect.ismethod(func):
|
|
data = data[1:]
|
|
defaults = func_info.defaults or tuple()
|
|
for i in xrange(len(defaults)):
|
|
data[i + len(data) - len(defaults)][1]['Default'] = defaults[i]
|
|
result = OrderedDict([
|
|
(name, typespec.ArgumentSpec(
|
|
declaration, self._namespace_resolver))
|
|
for name, declaration in data])
|
|
if '_context' in result:
|
|
del result['_context']
|
|
return result
|
|
|
|
def _prepare_body(self, body, name):
|
|
return macros.MethodBlock(body, name)
|
|
|
|
def __repr__(self):
|
|
return 'MuranoMethod({0}::{1})'.format(
|
|
self.murano_class.name, self.name)
|
|
|
|
def invoke(self, executor, this, parameters):
|
|
return self.murano_class.invoke(self.name, executor, this, parameters)
|