Import strutils from oslo, and convert to it.

The only change of behaviour here (according to the former glance
unit tests) is that 'T' now means True not False. I suspect that's
ok.

Change-Id: Icf98f913a3f78a1fe2f38a82a25a071c2da03739
This commit is contained in:
Michael Still 2013-05-17 10:05:14 +10:00
parent f09c52c8b0
commit 9356ea634d
7 changed files with 157 additions and 39 deletions

View File

@ -44,6 +44,7 @@ from glance.common import utils
from glance.common import wsgi from glance.common import wsgi
from glance import notifier from glance import notifier
import glance.openstack.common.log as logging import glance.openstack.common.log as logging
from glance.openstack.common import strutils
import glance.registry.client.v1.api as registry import glance.registry.client.v1.api as registry
from glance.store import (get_from_backend, from glance.store import (get_from_backend,
get_size_from_backend, get_size_from_backend,
@ -634,7 +635,7 @@ class Controller(controller.BaseController):
# properties NOT to be purged. However we also disable purging of # properties NOT to be purged. However we also disable purging of
# properties if an image file is being uploaded... # properties if an image file is being uploaded...
purge_props = req.headers.get('x-glance-registry-purge-props', True) purge_props = req.headers.get('x-glance-registry-purge-props', True)
purge_props = (utils.bool_from_string(purge_props) and purge_props = (strutils.bool_from_string(purge_props) and
image_data is None) image_data is None)
if image_data is not None and orig_status != 'queued': if image_data is not None and orig_status != 'queued':

View File

@ -41,6 +41,7 @@ from webob import exc
from glance.common import exception from glance.common import exception
import glance.openstack.common.log as logging import glance.openstack.common.log as logging
from glance.openstack.common import strutils
CONF = cfg.CONF CONF = cfg.CONF
@ -245,22 +246,10 @@ def get_image_meta_from_headers(response):
raise exception.Invalid raise exception.Invalid
for key in ('is_public', 'deleted', 'protected'): for key in ('is_public', 'deleted', 'protected'):
if key in result: if key in result:
result[key] = bool_from_string(result[key]) result[key] = strutils.bool_from_string(result[key])
return result return result
def bool_from_string(subject):
"""Interpret a string as a boolean-like value."""
if isinstance(subject, bool):
return subject
elif isinstance(subject, int):
return subject == 1
if hasattr(subject, 'startswith'): # str or unicode...
if subject.strip().lower() in ('true', 'on', '1', 'yes', 'y'):
return True
return False
def safe_mkdirs(path): def safe_mkdirs(path):
try: try:
os.makedirs(path) os.makedirs(path)

View File

@ -0,0 +1,150 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2011 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.
"""
System-level utilities and helper functions.
"""
import sys
from glance.openstack.common.gettextutils import _
TRUE_STRINGS = ('1', 't', 'true', 'on', 'y', 'yes')
FALSE_STRINGS = ('0', 'f', 'false', 'off', 'n', 'no')
def int_from_bool_as_string(subject):
"""
Interpret a string as a boolean and return either 1 or 0.
Any string value in:
('True', 'true', 'On', 'on', '1')
is interpreted as a boolean True.
Useful for JSON-decoded stuff and config file parsing
"""
return bool_from_string(subject) and 1 or 0
def bool_from_string(subject, strict=False):
"""
Interpret a string as a boolean.
A case-insensitive match is performed such that strings matching 't',
'true', 'on', 'y', 'yes', or '1' are considered True and, when
`strict=False`, anything else is considered False.
Useful for JSON-decoded stuff and config file parsing.
If `strict=True`, unrecognized values, including None, will raise a
ValueError which is useful when parsing values passed in from an API call.
Strings yielding False are 'f', 'false', 'off', 'n', 'no', or '0'.
"""
if not isinstance(subject, basestring):
subject = str(subject)
lowered = subject.strip().lower()
if lowered in TRUE_STRINGS:
return True
elif lowered in FALSE_STRINGS:
return False
elif strict:
acceptable = ', '.join(
"'%s'" % s for s in sorted(TRUE_STRINGS + FALSE_STRINGS))
msg = _("Unrecognized value '%(val)s', acceptable values are:"
" %(acceptable)s") % {'val': subject,
'acceptable': acceptable}
raise ValueError(msg)
else:
return False
def safe_decode(text, incoming=None, errors='strict'):
"""
Decodes incoming str using `incoming` if they're
not already unicode.
:param incoming: Text's current encoding
:param errors: Errors handling policy. See here for valid
values http://docs.python.org/2/library/codecs.html
:returns: text or a unicode `incoming` encoded
representation of it.
:raises TypeError: If text is not an isntance of basestring
"""
if not isinstance(text, basestring):
raise TypeError("%s can't be decoded" % type(text))
if isinstance(text, unicode):
return text
if not incoming:
incoming = (sys.stdin.encoding or
sys.getdefaultencoding())
try:
return text.decode(incoming, errors)
except UnicodeDecodeError:
# Note(flaper87) If we get here, it means that
# sys.stdin.encoding / sys.getdefaultencoding
# didn't return a suitable encoding to decode
# text. This happens mostly when global LANG
# var is not set correctly and there's no
# default encoding. In this case, most likely
# python will use ASCII or ANSI encoders as
# default encodings but they won't be capable
# of decoding non-ASCII characters.
#
# Also, UTF-8 is being used since it's an ASCII
# extension.
return text.decode('utf-8', errors)
def safe_encode(text, incoming=None,
encoding='utf-8', errors='strict'):
"""
Encodes incoming str/unicode using `encoding`. If
incoming is not specified, text is expected to
be encoded with current python's default encoding.
(`sys.getdefaultencoding`)
:param incoming: Text's current encoding
:param encoding: Expected encoding for text (Default UTF-8)
:param errors: Errors handling policy. See here for valid
values http://docs.python.org/2/library/codecs.html
:returns: text or a bytestring `encoding` encoded
representation of it.
:raises TypeError: If text is not an isntance of basestring
"""
if not isinstance(text, basestring):
raise TypeError("%s can't be encoded" % type(text))
if not incoming:
incoming = (sys.stdin.encoding or
sys.getdefaultencoding())
if isinstance(text, unicode):
return text.encode(encoding, errors)
elif text and encoding != incoming:
# Decode text before encoding it with `encoding`
text = safe_decode(text, incoming, errors)
return text.encode(encoding, errors)
return text

View File

@ -27,6 +27,7 @@ from glance.common import utils
from glance.common import wsgi from glance.common import wsgi
import glance.db import glance.db
import glance.openstack.common.log as logging import glance.openstack.common.log as logging
from glance.openstack.common import strutils
from glance.openstack.common import timeutils from glance.openstack.common import timeutils
from glance.openstack.common import uuidutils from glance.openstack.common import uuidutils
@ -273,7 +274,7 @@ class Controller(object):
deleted = req.params.get('deleted') deleted = req.params.get('deleted')
if deleted is None: if deleted is None:
return None return None
return utils.bool_from_string(deleted) return strutils.bool_from_string(deleted)
def show(self, req, id): def show(self, req, id):
"""Return data about the given image id.""" """Return data about the given image id."""

View File

@ -118,13 +118,6 @@ class TestUtils(test_utils.BaseTestCase):
self.assertRaises(exception.ImageSizeLimitExceeded, _consume_all_read) self.assertRaises(exception.ImageSizeLimitExceeded, _consume_all_read)
def test_bool_from_string(self):
actual = utils.bool_from_string('true')
self.assertEqual(True, actual)
actual = utils.bool_from_string(1)
self.assertEqual(True, actual)
def test_get_meta_from_headers(self): def test_get_meta_from_headers(self):
resp = webob.Response() resp = webob.Response()
resp.headers = {"x-image-meta-*": 'test'} resp.headers = {"x-image-meta-*": 'test'}

View File

@ -24,23 +24,6 @@ from glance.tests import utils as test_utils
class UtilsTestCase(test_utils.BaseTestCase): class UtilsTestCase(test_utils.BaseTestCase):
def test_bool_from_string(self):
true_values = ['True', True, 'true', 'TRUE', '1', 1, 'on',
'ON', 'y', 'yes', 'Y', 'YES']
i = 0
for value in true_values:
self.assertTrue(utils.bool_from_string(value),
"Got False for value: %r (%d)" % (value, i))
i = i + 1
false_values = ['False', False, 'false', 'T', 'F', 'FALSE',
'0', 0, 9, 'off', 'OFF', 'no', 'n', 'NO', 'N']
for value in false_values:
self.assertFalse(utils.bool_from_string(value),
"Got True for value: %r" % value)
def test_encryption(self): def test_encryption(self):
# Check that original plaintext and unencrypted ciphertext match # Check that original plaintext and unencrypted ciphertext match
# Check keys of the three allowed lengths # Check keys of the three allowed lengths

View File

@ -10,6 +10,7 @@ module=log
module=notifier module=notifier
module=policy module=policy
module=setup module=setup
module=strutils
module=timeutils module=timeutils
module=uuidutils module=uuidutils
module=version module=version