Py3 compatibility fixes

With this commit most of the Python 3 compatibility
issues in murano-engine are resolved.

If run on yaql with https://review.openstack.org/#/c/286110/
fix all of the unit tests except for one success.
The only failing test is base64 encoding/decoding test
which require rethink of resource management to get away
from string types for binary content

Change-Id: Iee87d27fe4f04118202de07f376d41fbf2c90f54
This commit is contained in:
Stan Lagun
2016-02-29 21:00:32 +03:00
committed by Alexander Tivelkov
parent f36fe4929d
commit 46ea32f4e8
24 changed files with 88 additions and 78 deletions

View File

@@ -1,20 +0,0 @@
# Copyright (c) 2013 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.
from message import Message
from mqclient import MqClient
from subscription import Subscription
__all__ = ['Message', 'Subscription', 'MqClient']

View File

@@ -17,7 +17,8 @@ import ssl as ssl_module
from eventlet import patcher from eventlet import patcher
from oslo_serialization import jsonutils from oslo_serialization import jsonutils
from subscription import Subscription
from murano.common.messaging import subscription
kombu = patcher.import_patched('kombu') kombu = patcher.import_patched('kombu')
@@ -100,4 +101,5 @@ class MqClient(object):
if not self._connected: if not self._connected:
raise RuntimeError('Not connected to RabbitMQ') raise RuntimeError('Not connected to RabbitMQ')
return Subscription(self._connection, queue, prefetch_count) return subscription.Subscription(
self._connection, queue, prefetch_count)

View File

@@ -14,6 +14,8 @@
import sys import sys
import six
from murano.dsl.principal_objects import stack_trace from murano.dsl.principal_objects import stack_trace
@@ -53,8 +55,13 @@ class MuranoPlException(Exception):
def from_python_exception(exception, context): def from_python_exception(exception, context):
stacktrace = stack_trace.create_stack_trace(context) stacktrace = stack_trace.create_stack_trace(context)
exception_type = type(exception) exception_type = type(exception)
names = ['{0}.{1}'.format(exception_type.__module__, builtins_module = 'builtins' if six.PY3 else 'exceptions'
exception_type.__name__)] module = exception_type.__module__
if module == builtins_module:
names = [exception_type.__name__]
else:
names = ['{0}.{1}'.format(exception_type.__module__,
exception_type.__name__)]
result = MuranoPlException( result = MuranoPlException(
names, str(exception), stacktrace) names, str(exception), stacktrace)

View File

@@ -194,7 +194,7 @@ class MuranoDslExecutor(object):
@staticmethod @staticmethod
def _canonize_parameters(arguments_scheme, args, kwargs): def _canonize_parameters(arguments_scheme, args, kwargs):
arg_names = arguments_scheme.keys() arg_names = list(arguments_scheme.keys())
parameter_values = utils.filter_parameters_dict(kwargs) parameter_values = utils.filter_parameters_dict(kwargs)
for i, arg in enumerate(args): for i, arg in enumerate(args):
name = arg_names[i] name = arg_names[i]

View File

@@ -17,7 +17,7 @@ import contextlib
import functools import functools
import inspect import inspect
import itertools import itertools
import string import re
import sys import sys
import uuid import uuid
@@ -267,7 +267,7 @@ def parse_version_spec(version_spec):
semantic_version.Spec('==' + str(version_spec))) semantic_version.Spec('==' + str(version_spec)))
if not version_spec: if not version_spec:
version_spec = '0' version_spec = '0'
version_spec = str(version_spec).translate(None, string.whitespace) version_spec = re.sub('\s+', '', str(version_spec))
if version_spec[0].isdigit(): if version_spec[0].isdigit():
version_spec = '==' + str(version_spec) version_spec = '==' + str(version_spec)
version_spec = semantic_version.Spec(version_spec) version_spec = semantic_version.Spec(version_spec)
@@ -532,3 +532,9 @@ def instantiate(data, owner, object_store, context, scope_type,
data['?']['id'] = uuid.uuid4().hex data['?']['id'] = uuid.uuid4().hex
return object_store.load(data, owner, context) return object_store.load(data, owner, context)
def function(c):
if hasattr(c, 'im_func'):
return c.im_func
return c

View File

@@ -27,7 +27,7 @@ class CodeBlock(expressions.DslExpression):
def __init__(self, body): def __init__(self, body):
if not isinstance(body, list): if not isinstance(body, list):
body = [body] body = [body]
self.code_block = map(expressions.parse_expression, body) self.code_block = list(map(expressions.parse_expression, body))
def execute(self, context): def execute(self, context):
for expr in self.code_block: for expr in self.code_block:

View File

@@ -177,7 +177,8 @@ class MuranoMethodArgument(dsl_types.MuranoMethodArgument, typespec.Spec,
self.murano_method.name, self.name, self.murano_method.name, self.name,
e.path, six.text_type(e)) e.path, six.text_type(e))
six.reraise(exceptions.ContractViolationException, six.reraise(exceptions.ContractViolationException,
msg, sys.exc_info()[2]) exceptions.ContractViolationException(msg),
sys.exc_info()[2])
@property @property
def murano_method(self): def murano_method(self):

View File

@@ -41,7 +41,8 @@ class MuranoProperty(dsl_types.MuranoProperty, typespec.Spec,
msg = u'[{0}.{1}{2}] {3}'.format( msg = u'[{0}.{1}{2}] {3}'.format(
self.declaring_type.name, self.name, e.path, six.text_type(e)) self.declaring_type.name, self.name, e.path, six.text_type(e))
six.reraise(exceptions.ContractViolationException, six.reraise(exceptions.ContractViolationException,
msg, sys.exc_info()[2]) exceptions.ContractViolationException(msg),
sys.exc_info()[2])
@property @property
def declaring_type(self): def declaring_type(self):

View File

@@ -304,7 +304,7 @@ class MuranoClass(dsl_types.MuranoClass, MuranoType, dslmeta.MetaProvider):
} }
for cls, parent in helpers.traverse( for cls, parent in helpers.traverse(
((self, parent) for parent in self._parents), ((self, parent) for parent in self._parents),
lambda (c, p): ((p, anc) for anc in p.declared_parents)): lambda cp: ((cp[1], anc) for anc in cp[1].declared_parents)):
if cls.package != parent.package: if cls.package != parent.package:
requirement = cls.package.requirements[parent.package.name] requirement = cls.package.requirements[parent.package.name]
aggregation.setdefault(parent.package.name, set()).add( aggregation.setdefault(parent.package.name, set()).add(

View File

@@ -12,8 +12,6 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
import sys
import six import six
from yaql.language import specs from yaql.language import specs
from yaql.language import utils from yaql.language import utils
@@ -244,7 +242,7 @@ class TypeScheme(object):
if len(spec) < 1: if len(spec) < 1:
return data return data
shift = 0 shift = 0
max_length = sys.maxint max_length = -1
min_length = 0 min_length = 0
if isinstance(spec[-1], int): if isinstance(spec[-1], int):
min_length = spec[-1] min_length = spec[-1]
@@ -254,10 +252,14 @@ class TypeScheme(object):
min_length = spec[-2] min_length = spec[-2]
shift += 1 shift += 1
if not min_length <= len(data) <= max_length: if max_length >= 0 and not min_length <= len(data) <= max_length:
raise exceptions.ContractViolationException( raise exceptions.ContractViolationException(
'Array length {0} is not within [{1}..{2}] range'.format( 'Array length {0} is not within [{1}..{2}] range'.format(
len(data), min_length, max_length)) len(data), min_length, max_length))
elif not min_length <= len(data):
raise exceptions.ContractViolationException(
'Array length {0} must not be less than {1}'.format(
len(data), min_length))
def map_func(): def map_func():
for index, item in enumerate(data): for index, item in enumerate(data):
@@ -284,7 +286,8 @@ class TypeScheme(object):
if isinstance(spec, dsl_types.YaqlExpression): if isinstance(spec, dsl_types.YaqlExpression):
child_context[''] = data child_context[''] = data
try: try:
return spec(context=child_context) result = spec(context=child_context)
return result
except exceptions.ContractViolationException as e: except exceptions.ContractViolationException as e:
e.path = path e.path = path
raise raise

View File

@@ -150,10 +150,9 @@ def get_function_definition(func, murano_method, original_name):
name, cls.__name__) name, cls.__name__)
body = func body = func
cls = murano_method.declaring_type.extension_class cls = murano_method.declaring_type.extension_class
if helpers.inspect_is_method(cls, original_name): if (helpers.inspect_is_method(cls, original_name) or
body = func.im_func helpers.inspect_is_classmethod(cls, original_name)):
if helpers.inspect_is_classmethod(cls, original_name): body = helpers.function(func)
body = func.im_func
fd = specs.get_function_definition( fd = specs.get_function_definition(
body, convention=CONVENTION, body, convention=CONVENTION,
parameter_type_func=param_type_func) parameter_type_func=param_type_func)
@@ -276,11 +275,11 @@ def get_class_factory_definition(cls, murano_class):
with helpers.contextual(__context): with helpers.contextual(__context):
return helpers.evaluate(cls(*args, **kwargs), __context) return helpers.evaluate(cls(*args, **kwargs), __context)
if hasattr(cls.__init__, 'im_func'): if '__init__' in cls.__dict__:
fd = specs.get_function_definition( fd = specs.get_function_definition(
cls.__init__.im_func, helpers.function(cls.__init__),
parameter_type_func=lambda name: _infer_parameter_type( parameter_type_func=lambda name: _infer_parameter_type(
name, cls.__init__.im_class.__name__), name, cls.__name__),
convention=CONVENTION) convention=CONVENTION)
else: else:
fd = specs.get_function_definition(lambda self: None) fd = specs.get_function_definition(lambda self: None)
@@ -302,12 +301,12 @@ def filter_parameters(__fd, *args, **kwargs):
position_args += 1 position_args += 1
args = args[:position_args] args = args[:position_args]
kwargs = kwargs.copy() kwargs = kwargs.copy()
for name in kwargs.keys(): for name in list(kwargs.keys()):
if not utils.is_keyword(name): if not utils.is_keyword(name):
del kwargs[name] del kwargs[name]
if '**' not in __fd.parameters: if '**' not in __fd.parameters:
names = {p.alias or p.name for p in six.itervalues(__fd.parameters)} names = {p.alias or p.name for p in six.itervalues(__fd.parameters)}
for name in kwargs.keys(): for name in list(kwargs.keys()):
if name not in names: if name not in names:
del kwargs[name] del kwargs[name]
return args, kwargs return args, kwargs

View File

@@ -127,8 +127,9 @@ class ApiPackageLoader(package_loader.MuranoPackageLoader):
self._lock_usage(package_definition) self._lock_usage(package_definition)
except LookupError: except LookupError:
exc_info = sys.exc_info() exc_info = sys.exc_info()
raise (exceptions.NoPackageForClassFound(class_name), six.reraise(exceptions.NoPackageForClassFound,
None, exc_info[2]) exceptions.NoPackageForClassFound(class_name),
exc_info[2])
return self._to_dsl_package( return self._to_dsl_package(
self._get_package_by_definition(package_definition)) self._get_package_by_definition(package_definition))
@@ -256,7 +257,9 @@ class ApiPackageLoader(package_loader.MuranoPackageLoader):
package_id, str(e) package_id, str(e)
) )
exc_info = sys.exc_info() exc_info = sys.exc_info()
six.reraise(pkg_exc.PackageLoadError(msg), None, exc_info[2]) six.reraise(pkg_exc.PackageLoadError,
pkg_exc.PackageLoadError(msg),
exc_info[2])
package_file = None package_file = None
try: try:
with tempfile.NamedTemporaryFile(delete=False) as package_file: with tempfile.NamedTemporaryFile(delete=False) as package_file:
@@ -278,7 +281,9 @@ class ApiPackageLoader(package_loader.MuranoPackageLoader):
except IOError: except IOError:
msg = 'Unable to extract package data for %s' % package_id msg = 'Unable to extract package data for %s' % package_id
exc_info = sys.exc_info() exc_info = sys.exc_info()
raise pkg_exc.PackageLoadError(msg), None, exc_info[2] six.reraise(pkg_exc.PackageLoadError,
pkg_exc.PackageLoadError(msg),
exc_info[2])
finally: finally:
try: try:
if package_file: if package_file:
@@ -296,7 +301,6 @@ class ApiPackageLoader(package_loader.MuranoPackageLoader):
if not package_directory: if not package_directory:
return return
pkg_ids_listed = set()
try: try:
pkg_ids_listed = set(os.listdir(package_directory)) pkg_ids_listed = set(os.listdir(package_directory))
except OSError: except OSError:

View File

@@ -25,7 +25,7 @@ import six
from yaql import specs from yaql import specs
import murano.common.exceptions as exceptions import murano.common.exceptions as exceptions
import murano.common.messaging as messaging from murano.common.messaging import message
from murano.dsl import dsl from murano.dsl import dsl
import murano.engine.system.common as common import murano.engine.system.common as common
@@ -75,7 +75,7 @@ class Agent(object):
'by the server configuration') 'by the server configuration')
def _prepare_message(self, template, msg_id): def _prepare_message(self, template, msg_id):
msg = messaging.Message() msg = message.Message()
msg.body = template msg.body = template
msg.id = msg_id msg.id = msg_id
return msg return msg

View File

@@ -15,7 +15,7 @@
from oslo_config import cfg from oslo_config import cfg
import murano.common.messaging as messaging from murano.common.messaging import mqclient
CONF = cfg.CONF CONF = cfg.CONF
@@ -31,4 +31,4 @@ def create_rmq_client():
'ssl': rabbitmq.ssl, 'ssl': rabbitmq.ssl,
'ca_certs': rabbitmq.ca_certs.strip() or None 'ca_certs': rabbitmq.ca_certs.strip() or None
} }
return messaging.MqClient(**connection_params) return mqclient.MqClient(**connection_params)

View File

@@ -13,8 +13,6 @@
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
import exceptions
from oslo_log import log as logging from oslo_log import log as logging
from yaql.language import specs from yaql.language import specs
from yaql.language import yaqltypes from yaql.language import yaqltypes
@@ -98,7 +96,7 @@ class Logger(object):
""" """
try: try:
message = format_function(message, *args, **kwargs) message = format_function(message, *args, **kwargs)
except (exceptions.IndexError, exceptions.KeyError): except (IndexError, KeyError):
# NOTE(akhivin): we do not want break program workflow # NOTE(akhivin): we do not want break program workflow
# even formatting parameters are incorrect # even formatting parameters are incorrect
self._underlying_logger.warning( self._underlying_logger.warning(

View File

@@ -72,7 +72,8 @@ class NetworkExplorer(object):
if uuidutils.is_uuid_like(external_network) \ if uuidutils.is_uuid_like(external_network) \
else {'name': external_network} else {'name': external_network}
networks = self._client.list_networks(**kwargs).get('networks') networks = self._client.list_networks(**kwargs).get('networks')
ext_nets = filter(lambda n: n['router:external'], networks) ext_nets = list(filter(lambda n: n['router:external'],
networks))
if len(ext_nets) == 0: if len(ext_nets) == 0:
raise KeyError('Router %s could not be created, ' raise KeyError('Router %s could not be created, '
'no external network found' % router_name) 'no external network found' % router_name)

View File

@@ -133,7 +133,7 @@ def _int2base(x, base):
:param base: number base, max value is 36 :param base: number base, max value is 36
:return: integer converted to the specified base :return: integer converted to the specified base
""" """
digs = string.digits + string.lowercase digs = string.digits + string.ascii_lowercase
if x < 0: if x < 0:
sign = -1 sign = -1
elif x == 0: elif x == 0:
@@ -144,7 +144,7 @@ def _int2base(x, base):
digits = [] digits = []
while x: while x:
digits.append(digs[x % base]) digits.append(digs[x % base])
x /= base x //= base
if sign < 0: if sign < 0:
digits.append('-') digits.append('-')
digits.reverse() digits.reverse()
@@ -163,7 +163,7 @@ def random_name():
counter = _random_string_counter or 1 counter = _random_string_counter or 1
# generate first 5 random chars # generate first 5 random chars
prefix = ''.join(random.choice(string.lowercase) for _ in range(5)) prefix = ''.join(random.choice(string.ascii_lowercase) for _ in range(5))
# convert timestamp to higher base to shorten hostname string # convert timestamp to higher base to shorten hostname string
# (up to 8 chars) # (up to 8 chars)
timestamp = _int2base(int(time.time() * 1000), 36)[:8] timestamp = _int2base(int(time.time() * 1000), 36)[:8]

View File

@@ -19,6 +19,7 @@ import sys
import tempfile import tempfile
import zipfile import zipfile
import six
import yaml import yaml
from murano.common.plugins import package_types_loader from murano.common.plugins import package_types_loader
@@ -91,9 +92,11 @@ def load_from_dir(source_directory, filename='manifest.yaml'):
content = yaml.safe_load(stream) content = yaml.safe_load(stream)
except Exception as ex: except Exception as ex:
trace = sys.exc_info()[2] trace = sys.exc_info()[2]
raise e.PackageLoadError( six.reraise(
"Unable to load due to '{0}'".format(str(ex))), None, trace e.PackageLoadError,
if content: e.PackageLoadError("Unable to load due to '{0}'".format(ex)),
trace)
else:
format_spec = str(content.get('Format') or 'MuranoPL/1.0') format_spec = str(content.get('Format') or 'MuranoPL/1.0')
if format_spec[0].isdigit(): if format_spec[0].isdigit():
format_spec = 'MuranoPL/' + format_spec format_spec = 'MuranoPL/' + format_spec

View File

@@ -37,7 +37,7 @@ class MuranoPlPackage(package_base.PackageBase):
full_path = os.path.join(self._source_directory, 'UI', self._ui_file) full_path = os.path.join(self._source_directory, 'UI', self._ui_file)
if not os.path.isfile(full_path): if not os.path.isfile(full_path):
return None return None
with open(full_path) as stream: with open(full_path, 'rb') as stream:
return stream.read() return stream.read()
@property @property
@@ -53,7 +53,7 @@ class MuranoPlPackage(package_base.PackageBase):
if not os.path.isfile(full_path): if not os.path.isfile(full_path):
raise exceptions.PackageClassLoadError( raise exceptions.PackageClassLoadError(
name, 'File with class definition not found') name, 'File with class definition not found')
with open(full_path) as stream: with open(full_path, 'rb') as stream:
return stream.read(), full_path return stream.read(), full_path
@property @property

View File

@@ -20,6 +20,7 @@ import re
import sys import sys
import semantic_version import semantic_version
import six
from murano.packages import exceptions from murano.packages import exceptions
from murano.packages import package from murano.packages import package
@@ -135,8 +136,10 @@ class PackageBase(package.Package):
return stream.read() return stream.read()
except Exception as ex: except Exception as ex:
trace = sys.exc_info()[2] trace = sys.exc_info()[2]
raise exceptions.PackageLoadError( six.reraise(exceptions.PackageLoadError,
'Unable to load {0}: {1}'.format(what_image, ex)), None, trace exceptions.PackageLoadError(
'Unable to load {0}: {1}'.format(what_image, ex)),
trace)
@staticmethod @staticmethod
def _check_full_name(full_name): def _check_full_name(full_name):

View File

@@ -105,8 +105,10 @@ class Runner(object):
original_exception, dsl_exception.MuranoPlException): original_exception, dsl_exception.MuranoPlException):
exc_traceback = getattr( exc_traceback = getattr(
e, 'original_traceback', None) or sys.exc_info()[2] e, 'original_traceback', None) or sys.exc_info()[2]
raise type(original_exception), original_exception, \ six.reraise(
exc_traceback type(original_exception),
original_exception,
exc_traceback)
raise raise
def __getattr__(self, item): def __getattr__(self, item):

View File

@@ -88,7 +88,7 @@ class TestPackageLoader(package_loader.MuranoPackageLoader):
self._load_classes(class_def_file) self._load_classes(class_def_file)
def _load_classes(self, class_def_file): def _load_classes(self, class_def_file):
with open(class_def_file) as stream: with open(class_def_file, 'rb') as stream:
data_lst = self._yaml_loader(stream.read(), class_def_file) data_lst = self._yaml_loader(stream.read(), class_def_file)
last_ns = {} last_ns = {}

View File

@@ -67,29 +67,29 @@ class TestContracts(test_case.DslTestCase):
def test_bool_contract(self): def test_bool_contract(self):
result = self._runner.testBoolContract(True) result = self._runner.testBoolContract(True)
self.assertIsInstance(result, bool) self.assertIsInstance(result, bool)
self.assertIs(result, True) self.assertTrue(result)
result = self._runner.testBoolContract(False) result = self._runner.testBoolContract(False)
self.assertIsInstance(result, bool) self.assertIsInstance(result, bool)
self.assertIs(result, False) self.assertFalse(result)
def test_bool_from_int_contract(self): def test_bool_from_int_contract(self):
result = self._runner.testBoolContract(10) result = self._runner.testBoolContract(10)
self.assertIsInstance(result, bool) self.assertIsInstance(result, bool)
self.assertIs(result, True) self.assertTrue(result)
result = self._runner.testBoolContract(0) result = self._runner.testBoolContract(0)
self.assertIsInstance(result, bool) self.assertIsInstance(result, bool)
self.assertIs(result, False) self.assertFalse(result)
def test_bool_from_string_contract(self): def test_bool_from_string_contract(self):
result = self._runner.testBoolContract('something') result = self._runner.testBoolContract('something')
self.assertIsInstance(result, bool) self.assertIsInstance(result, bool)
self.assertIs(result, True) self.assertTrue(result)
result = self._runner.testBoolContract('') result = self._runner.testBoolContract('')
self.assertIsInstance(result, bool) self.assertIsInstance(result, bool)
self.assertIs(result, False) self.assertFalse(result)
def test_bool_null_contract(self): def test_bool_null_contract(self):
self.assertIsNone(self._runner.testIntContract(None)) self.assertIsNone(self._runner.testIntContract(None))

View File

@@ -80,7 +80,7 @@ class TestExceptions(test_case.DslTestCase):
self.assertThat( self.assertThat(
call_stack, call_stack,
matchers.StartsWith( matchers.StartsWith(
'exceptions.LookupError: just random Python exception')) 'LookupError: just random Python exception'))
self.assertIsInstance(e.original_exception, LookupError) self.assertIsInstance(e.original_exception, LookupError)