From 50d438384aa88254c55ac7f0f3b79e37374545f6 Mon Sep 17 00:00:00 2001 From: Joshua Harlow Date: Wed, 9 Oct 2013 19:17:51 -0700 Subject: [PATCH] Update oslo copy and bring over versionutils Change-Id: I93ab20ae26033574e1f25ecc8276ffe291994ce6 --- openstack-common.conf | 1 + taskflow/openstack/common/excutils.py | 2 +- taskflow/openstack/common/gettextutils.py | 62 +++++++++++++++++++---- taskflow/openstack/common/jsonutils.py | 3 ++ taskflow/openstack/common/timeutils.py | 7 ++- taskflow/openstack/common/versionutils.py | 45 ++++++++++++++++ taskflow/utils/misc.py | 17 ------- tools/install_venv_common.py | 42 +-------------- 8 files changed, 107 insertions(+), 72 deletions(-) create mode 100644 taskflow/openstack/common/versionutils.py diff --git a/openstack-common.conf b/openstack-common.conf index 2b771ffc..316ef96f 100644 --- a/openstack-common.conf +++ b/openstack-common.conf @@ -7,6 +7,7 @@ module=install_venv_common module=jsonutils module=timeutils module=uuidutils +module=versionutils # The base module to hold the copy of openstack.common base=taskflow diff --git a/taskflow/openstack/common/excutils.py b/taskflow/openstack/common/excutils.py index 8f4f6b15..ec2d6ba0 100644 --- a/taskflow/openstack/common/excutils.py +++ b/taskflow/openstack/common/excutils.py @@ -79,7 +79,7 @@ def forever_retry_uncaught_exceptions(infunc): try: return infunc(*args, **kwargs) except Exception as exc: - this_exc_message = unicode(exc) + this_exc_message = six.u(str(exc)) if this_exc_message == last_exc_message: exc_count += 1 else: diff --git a/taskflow/openstack/common/gettextutils.py b/taskflow/openstack/common/gettextutils.py index 54a7b338..2bfd38c1 100644 --- a/taskflow/openstack/common/gettextutils.py +++ b/taskflow/openstack/common/gettextutils.py @@ -60,6 +60,8 @@ def _(msg): if USE_LAZY: return Message(msg, 'taskflow') else: + if six.PY3: + return _t.gettext(msg) return _t.ugettext(msg) @@ -105,13 +107,17 @@ def install(domain, lazy=False): """ return Message(msg, domain) - import __builtin__ - __builtin__.__dict__['_'] = _lazy_gettext + from six import moves + moves.builtins.__dict__['_'] = _lazy_gettext else: localedir = '%s_LOCALEDIR' % domain.upper() - gettext.install(domain, - localedir=os.environ.get(localedir), - unicode=True) + if six.PY3: + gettext.install(domain, + localedir=os.environ.get(localedir)) + else: + gettext.install(domain, + localedir=os.environ.get(localedir), + unicode=True) class Message(_userString.UserString, object): @@ -121,8 +127,8 @@ class Message(_userString.UserString, object): self._msg = msg self._left_extra_msg = '' self._right_extra_msg = '' + self._locale = None self.params = None - self.locale = None self.domain = domain @property @@ -142,8 +148,13 @@ class Message(_userString.UserString, object): localedir=localedir, fallback=True) + if six.PY3: + ugettext = lang.gettext + else: + ugettext = lang.ugettext + full_msg = (self._left_extra_msg + - lang.ugettext(self._msg) + + ugettext(self._msg) + self._right_extra_msg) if self.params is not None: @@ -151,6 +162,33 @@ class Message(_userString.UserString, object): return six.text_type(full_msg) + @property + def locale(self): + return self._locale + + @locale.setter + def locale(self, value): + self._locale = value + if not self.params: + return + + # This Message object may have been constructed with one or more + # Message objects as substitution parameters, given as a single + # Message, or a tuple or Map containing some, so when setting the + # locale for this Message we need to set it for those Messages too. + if isinstance(self.params, Message): + self.params.locale = value + return + if isinstance(self.params, tuple): + for param in self.params: + if isinstance(param, Message): + param.locale = value + return + if isinstance(self.params, dict): + for param in self.params.values(): + if isinstance(param, Message): + param.locale = value + def _save_dictionary_parameter(self, dict_param): full_msg = self.data # look for %(blah) fields in string; @@ -169,7 +207,7 @@ class Message(_userString.UserString, object): params[key] = copy.deepcopy(dict_param[key]) except TypeError: # cast uncopyable thing to unicode string - params[key] = unicode(dict_param[key]) + params[key] = six.text_type(dict_param[key]) return params @@ -188,7 +226,7 @@ class Message(_userString.UserString, object): try: self.params = copy.deepcopy(other) except TypeError: - self.params = unicode(other) + self.params = six.text_type(other) return self @@ -197,11 +235,13 @@ class Message(_userString.UserString, object): return self.data def __str__(self): + if six.PY3: + return self.__unicode__() return self.data.encode('utf-8') def __getstate__(self): to_copy = ['_msg', '_right_extra_msg', '_left_extra_msg', - 'domain', 'params', 'locale'] + 'domain', 'params', '_locale'] new_dict = self.__dict__.fromkeys(to_copy) for attr in to_copy: new_dict[attr] = copy.deepcopy(self.__dict__[attr]) @@ -293,7 +333,7 @@ def get_localized_message(message, user_locale): if isinstance(message, Message): if user_locale: message.locale = user_locale - return unicode(message) + return six.text_type(message) else: return message diff --git a/taskflow/openstack/common/jsonutils.py b/taskflow/openstack/common/jsonutils.py index 194df47b..c3b1be97 100644 --- a/taskflow/openstack/common/jsonutils.py +++ b/taskflow/openstack/common/jsonutils.py @@ -46,6 +46,7 @@ except ImportError: import six +from taskflow.openstack.common import gettextutils from taskflow.openstack.common import importutils from taskflow.openstack.common import timeutils @@ -135,6 +136,8 @@ def to_primitive(value, convert_instances=False, convert_datetime=True, if convert_datetime and isinstance(value, datetime.datetime): return timeutils.strtime(value) + elif isinstance(value, gettextutils.Message): + return value.data elif hasattr(value, 'iteritems'): return recursive(dict(value.iteritems()), level=level + 1) elif hasattr(value, '__iter__'): diff --git a/taskflow/openstack/common/timeutils.py b/taskflow/openstack/common/timeutils.py index 60f02bcb..98d877d5 100644 --- a/taskflow/openstack/common/timeutils.py +++ b/taskflow/openstack/common/timeutils.py @@ -117,12 +117,15 @@ def iso8601_from_timestamp(timestamp): utcnow.override_time = None -def set_time_override(override_time=datetime.datetime.utcnow()): +def set_time_override(override_time=None): """Overrides utils.utcnow. Make it return a constant time or a list thereof, one at a time. + + :param override_time: datetime instance or list thereof. If not + given, defaults to the current UTC time. """ - utcnow.override_time = override_time + utcnow.override_time = override_time or datetime.datetime.utcnow() def advance_time_delta(timedelta): diff --git a/taskflow/openstack/common/versionutils.py b/taskflow/openstack/common/versionutils.py new file mode 100644 index 00000000..f7b1f8a8 --- /dev/null +++ b/taskflow/openstack/common/versionutils.py @@ -0,0 +1,45 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright (c) 2013 OpenStack Foundation +# All Rights Reserved. +# +# 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. + +""" +Helpers for comparing version strings. +""" + +import pkg_resources + + +def is_compatible(requested_version, current_version, same_major=True): + """Determine whether `requested_version` is satisfied by + `current_version`; in other words, `current_version` is >= + `requested_version`. + + :param requested_version: version to check for compatibility + :param current_version: version to check against + :param same_major: if True, the major version must be identical between + `requested_version` and `current_version`. This is used when a + major-version difference indicates incompatibility between the two + versions. Since this is the common-case in practice, the default is + True. + :returns: True if compatible, False if not + """ + requested_parts = pkg_resources.parse_version(requested_version) + current_parts = pkg_resources.parse_version(current_version) + + if same_major and (requested_parts[0] != current_parts[0]): + return False + + return current_parts >= requested_parts diff --git a/taskflow/utils/misc.py b/taskflow/utils/misc.py index fe848637..4e6b5978 100644 --- a/taskflow/utils/misc.py +++ b/taskflow/utils/misc.py @@ -17,8 +17,6 @@ # License for the specific language governing permissions and limitations # under the License. -from distutils import version - import collections import copy import errno @@ -123,21 +121,6 @@ def as_int(obj, quiet=False): return obj -def is_version_compatible(version_1, version_2): - """Checks for major version compatibility of two *string* versions.""" - try: - version_1_tmp = version.StrictVersion(version_1) - version_2_tmp = version.StrictVersion(version_2) - except ValueError: - version_1_tmp = version.LooseVersion(version_1) - version_2_tmp = version.LooseVersion(version_2) - version_1 = version_1_tmp - version_2 = version_2_tmp - if version_1 == version_2 or version_1.version[0] == version_2.version[0]: - return True - return False - - # Taken from oslo-incubator file-utils but since that module pulls in a large # amount of other files it does not seem so useful to include that full # module just for this function. diff --git a/tools/install_venv_common.py b/tools/install_venv_common.py index 0999e2c2..1bab88a3 100644 --- a/tools/install_venv_common.py +++ b/tools/install_venv_common.py @@ -119,11 +119,7 @@ class InstallVenv(object): self.pip_install('setuptools') self.pip_install('pbr') - self.pip_install('-r', self.requirements) - self.pip_install('-r', self.test_requirements) - - def post_process(self): - self.get_distro().post_process() + self.pip_install('-r', self.requirements, '-r', self.test_requirements) def parse_args(self, argv): """Parses command-line arguments.""" @@ -157,14 +153,6 @@ class Distro(InstallVenv): ' requires virtualenv, please install it using your' ' favorite package management tool' % self.project) - def post_process(self): - """Any distribution-specific post-processing gets done here. - - In particular, this is useful for applying patches to code inside - the venv. - """ - pass - class Fedora(Distro): """This covers all Fedora-based distributions. @@ -176,10 +164,6 @@ class Fedora(Distro): return self.run_command_with_code(['rpm', '-q', pkg], check_exit_code=False)[1] == 0 - def apply_patch(self, originalfile, patchfile): - self.run_command(['patch', '-N', originalfile, patchfile], - check_exit_code=False) - def install_virtualenv(self): if self.check_cmd('virtualenv'): return @@ -188,27 +172,3 @@ class Fedora(Distro): self.die("Please install 'python-virtualenv'.") super(Fedora, self).install_virtualenv() - - def post_process(self): - """Workaround for a bug in eventlet. - - This currently affects RHEL6.1, but the fix can safely be - applied to all RHEL and Fedora distributions. - - This can be removed when the fix is applied upstream. - - Nova: https://bugs.launchpad.net/nova/+bug/884915 - Upstream: https://bitbucket.org/eventlet/eventlet/issue/89 - RHEL: https://bugzilla.redhat.com/958868 - """ - - if os.path.exists('contrib/redhat-eventlet.patch'): - # Install "patch" program if it's not there - if not self.check_pkg('patch'): - self.die("Please install 'patch'.") - - # Apply the eventlet patch - self.apply_patch(os.path.join(self.venv, 'lib', self.py_version, - 'site-packages', - 'eventlet/green/subprocess.py'), - 'contrib/redhat-eventlet.patch')