summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJenkins <jenkins@review.openstack.org>2014-02-28 15:13:56 +0000
committerGerrit Code Review <review@openstack.org>2014-02-28 15:13:56 +0000
commiteef94a62484a21f748eec2c655f3d062c3af7465 (patch)
tree184bc4177ad03fdc2a38e371c86d66d5ba7a8533
parent716d9a3af3733b41909d6579ae8e4bfde2dd7eb5 (diff)
parente0272b0578d2a4f5bd75e68baee1b56f49931266 (diff)
downloadpython-novaclient-eef94a62484a21f748eec2c655f3d062c3af7465.tar.gz
Merge "oslo-sync of low hanging fruit"
-rw-r--r--novaclient/openstack/common/__init__.py2
-rw-r--r--novaclient/openstack/common/gettextutils.py55
-rw-r--r--novaclient/openstack/common/importutils.py7
-rw-r--r--novaclient/openstack/common/strutils.py84
-rw-r--r--novaclient/openstack/common/timeutils.py2
-rw-r--r--openstack-common.conf2
6 files changed, 117 insertions, 35 deletions
diff --git a/novaclient/openstack/common/__init__.py b/novaclient/openstack/common/__init__.py
index e69de29b..2a00f3bc 100644
--- a/novaclient/openstack/common/__init__.py
+++ b/novaclient/openstack/common/__init__.py
@@ -0,0 +1,2 @@
+import six
+six.add_move(six.MovedModule('mox', 'mox', 'mox3.mox'))
diff --git a/novaclient/openstack/common/gettextutils.py b/novaclient/openstack/common/gettextutils.py
index 27f7ec42..98234827 100644
--- a/novaclient/openstack/common/gettextutils.py
+++ b/novaclient/openstack/common/gettextutils.py
@@ -23,6 +23,7 @@ Usual usage in an openstack.common module:
"""
import copy
+import functools
import gettext
import locale
from logging import handlers
@@ -35,6 +36,17 @@ import six
_localedir = os.environ.get('novaclient'.upper() + '_LOCALEDIR')
_t = gettext.translation('novaclient', localedir=_localedir, fallback=True)
+# We use separate translation catalogs for each log level, so set up a
+# mapping between the log level name and the translator. The domain
+# for the log level is project_name + "-log-" + log_level so messages
+# for each level end up in their own catalog.
+_t_log_levels = dict(
+ (level, gettext.translation('novaclient' + '-log-' + level,
+ localedir=_localedir,
+ fallback=True))
+ for level in ['info', 'warning', 'error', 'critical']
+)
+
_AVAILABLE_LANGUAGES = {}
USE_LAZY = False
@@ -60,6 +72,28 @@ def _(msg):
return _t.ugettext(msg)
+def _log_translation(msg, level):
+ """Build a single translation of a log message
+ """
+ if USE_LAZY:
+ return Message(msg, domain='novaclient' + '-log-' + level)
+ else:
+ translator = _t_log_levels[level]
+ if six.PY3:
+ return translator.gettext(msg)
+ return translator.ugettext(msg)
+
+# Translators for log levels.
+#
+# The abbreviated names are meant to reflect the usual use of a short
+# name like '_'. The "L" is for "log" and the other letter comes from
+# the level.
+_LI = functools.partial(_log_translation, level='info')
+_LW = functools.partial(_log_translation, level='warning')
+_LE = functools.partial(_log_translation, level='error')
+_LC = functools.partial(_log_translation, level='critical')
+
+
def install(domain, lazy=False):
"""Install a _() function using the given translation domain.
@@ -118,7 +152,8 @@ class Message(six.text_type):
and can be treated as such.
"""
- def __new__(cls, msgid, msgtext=None, params=None, domain='novaclient', *args):
+ def __new__(cls, msgid, msgtext=None, params=None,
+ domain='novaclient', *args):
"""Create a new Message object.
In order for translation to work gettext requires a message ID, this
@@ -297,9 +332,27 @@ def get_available_languages(domain):
list_identifiers = (getattr(localedata, 'list', None) or
getattr(localedata, 'locale_identifiers'))
locale_identifiers = list_identifiers()
+
for i in locale_identifiers:
if find(i) is not None:
language_list.append(i)
+
+ # NOTE(luisg): Babel>=1.0,<1.3 has a bug where some OpenStack supported
+ # locales (e.g. 'zh_CN', and 'zh_TW') aren't supported even though they
+ # are perfectly legitimate locales:
+ # https://github.com/mitsuhiko/babel/issues/37
+ # In Babel 1.3 they fixed the bug and they support these locales, but
+ # they are still not explicitly "listed" by locale_identifiers().
+ # That is why we add the locales here explicitly if necessary so that
+ # they are listed as supported.
+ aliases = {'zh': 'zh_CN',
+ 'zh_Hant_HK': 'zh_HK',
+ 'zh_Hant': 'zh_TW',
+ 'fil': 'tl_PH'}
+ for (locale, alias) in six.iteritems(aliases):
+ if locale in language_list and alias not in language_list:
+ language_list.append(alias)
+
_AVAILABLE_LANGUAGES[domain] = language_list
return copy.copy(language_list)
diff --git a/novaclient/openstack/common/importutils.py b/novaclient/openstack/common/importutils.py
index 4fd9ae2b..e35b088a 100644
--- a/novaclient/openstack/common/importutils.py
+++ b/novaclient/openstack/common/importutils.py
@@ -58,6 +58,13 @@ def import_module(import_str):
return sys.modules[import_str]
+def import_versioned_module(version, submodule=None):
+ module = 'novaclient.v%s' % version
+ if submodule:
+ module = '.'.join((module, submodule))
+ return import_module(module)
+
+
def try_import(import_str, default=None):
"""Try to import a module and if it fails return default."""
try:
diff --git a/novaclient/openstack/common/strutils.py b/novaclient/openstack/common/strutils.py
index c01de557..1383fbb7 100644
--- a/novaclient/openstack/common/strutils.py
+++ b/novaclient/openstack/common/strutils.py
@@ -17,6 +17,7 @@
System-level utilities and helper functions.
"""
+import math
import re
import sys
import unicodedata
@@ -26,16 +27,21 @@ import six
from novaclient.openstack.common.gettextutils import _
-# Used for looking up extensions of text
-# to their 'multiplied' byte amount
-BYTE_MULTIPLIERS = {
- '': 1,
- 't': 1024 ** 4,
- 'g': 1024 ** 3,
- 'm': 1024 ** 2,
- 'k': 1024,
+UNIT_PREFIX_EXPONENT = {
+ 'k': 1,
+ 'K': 1,
+ 'Ki': 1,
+ 'M': 2,
+ 'Mi': 2,
+ 'G': 3,
+ 'Gi': 3,
+ 'T': 4,
+ 'Ti': 4,
+}
+UNIT_SYSTEM_INFO = {
+ 'IEC': (1024, re.compile(r'(^[-+]?\d*\.?\d+)([KMGT]i?)?(b|bit|B)$')),
+ 'SI': (1000, re.compile(r'(^[-+]?\d*\.?\d+)([kMGT])?(b|bit|B)$')),
}
-BYTE_REGEX = re.compile(r'(^-?\d+)(\D*)')
TRUE_STRINGS = ('1', 't', 'true', 'on', 'y', 'yes')
FALSE_STRINGS = ('0', 'f', 'false', 'off', 'n', 'no')
@@ -102,7 +108,7 @@ def safe_decode(text, incoming=None, errors='strict'):
:raises TypeError: If text is not an instance of str
"""
if not isinstance(text, six.string_types):
- raise TypeError(_("%s can't be decoded") % type(text))
+ raise TypeError("%s can't be decoded" % type(text))
if isinstance(text, six.text_type):
return text
@@ -145,7 +151,7 @@ def safe_encode(text, incoming=None,
:raises TypeError: If text is not an instance of str
"""
if not isinstance(text, six.string_types):
- raise TypeError(_("%s can't be encoded") % type(text))
+ raise TypeError("%s can't be encoded" % type(text))
if not incoming:
incoming = (sys.stdin.encoding or
@@ -167,34 +173,50 @@ def safe_encode(text, incoming=None,
return text
-def to_bytes(text, default=0):
- """Converts a string into an integer of bytes.
+def string_to_bytes(text, unit_system='IEC', return_int=False):
+ """Converts a string into an float representation of bytes.
+
+ The units supported for IEC ::
+
+ Kb(it), Kib(it), Mb(it), Mib(it), Gb(it), Gib(it), Tb(it), Tib(it)
+ KB, KiB, MB, MiB, GB, GiB, TB, TiB
+
+ The units supported for SI ::
+
+ kb(it), Mb(it), Gb(it), Tb(it)
+ kB, MB, GB, TB
- Looks at the last characters of the text to determine
- what conversion is needed to turn the input text into a byte number.
- Supports "B, K(B), M(B), G(B), and T(B)". (case insensitive)
+ Note that the SI unit system does not support capital letter 'K'
:param text: String input for bytes size conversion.
- :param default: Default return value when text is blank.
+ :param unit_system: Unit system for byte size conversion.
+ :param return_int: If True, returns integer representation of text
+ in bytes. (default: decimal)
+ :returns: Numerical representation of text in bytes.
+ :raises ValueError: If text has an invalid value.
"""
- match = BYTE_REGEX.search(text)
+ try:
+ base, reg_ex = UNIT_SYSTEM_INFO[unit_system]
+ except KeyError:
+ msg = _('Invalid unit system: "%s"') % unit_system
+ raise ValueError(msg)
+ match = reg_ex.match(text)
if match:
- magnitude = int(match.group(1))
- mult_key_org = match.group(2)
- if not mult_key_org:
- return magnitude
- elif text:
+ magnitude = float(match.group(1))
+ unit_prefix = match.group(2)
+ if match.group(3) in ['b', 'bit']:
+ magnitude /= 8
+ else:
msg = _('Invalid string format: %s') % text
- raise TypeError(msg)
+ raise ValueError(msg)
+ if not unit_prefix:
+ res = magnitude
else:
- return default
- mult_key = mult_key_org.lower().replace('b', '', 1)
- multiplier = BYTE_MULTIPLIERS.get(mult_key)
- if multiplier is None:
- msg = _('Unknown byte multiplier: %s') % mult_key_org
- raise TypeError(msg)
- return magnitude * multiplier
+ res = magnitude * pow(base, UNIT_PREFIX_EXPONENT[unit_prefix])
+ if return_int:
+ return int(math.ceil(res))
+ return res
def to_slug(value, incoming=None, errors="strict"):
diff --git a/novaclient/openstack/common/timeutils.py b/novaclient/openstack/common/timeutils.py
index d5ed81d3..52688a02 100644
--- a/novaclient/openstack/common/timeutils.py
+++ b/novaclient/openstack/common/timeutils.py
@@ -114,7 +114,7 @@ def utcnow():
def iso8601_from_timestamp(timestamp):
- """Returns a iso8601 formated date from timestamp."""
+ """Returns a iso8601 formatted date from timestamp."""
return isotime(datetime.datetime.utcfromtimestamp(timestamp))
diff --git a/openstack-common.conf b/openstack-common.conf
index 15081471..e6543063 100644
--- a/openstack-common.conf
+++ b/openstack-common.conf
@@ -1,12 +1,10 @@
[DEFAULT]
# The list of modules to copy from openstack-common
-module=install_venv_common
module=jsonutils
module=strutils
module=timeutils
module=uuidutils
-module=py3kcompat
module=apiclient
module=importutils
module=cliutils