diff options
| author | Jenkins <jenkins@review.openstack.org> | 2013-05-15 00:39:24 +0000 |
|---|---|---|
| committer | Gerrit Code Review <review@openstack.org> | 2013-05-15 00:39:24 +0000 |
| commit | e585ef4871a001c3b3393e35017f24fcf44a523e (patch) | |
| tree | 7479dd5022f3d6cf97bf1871bef17cfb1b2a9a49 | |
| parent | 3e0114f570d97c47b1b8eefce0bcd27146098b8d (diff) | |
| parent | 536c39e8e315af4b1823cfa378f3db441a212b1a (diff) | |
| download | oslo-e585ef4871a001c3b3393e35017f24fcf44a523e.tar.gz oslo-e585ef4871a001c3b3393e35017f24fcf44a523e.tar.xz oslo-e585ef4871a001c3b3393e35017f24fcf44a523e.zip | |
Merge "Add 't', 'y', and `strict` to `bool_from_string`"
| -rw-r--r-- | openstack/common/strutils.py | 45 | ||||
| -rw-r--r-- | tests/unit/test_strutils.py | 61 |
2 files changed, 92 insertions, 14 deletions
diff --git a/openstack/common/strutils.py b/openstack/common/strutils.py index d6dfb13..6d227c6 100644 --- a/openstack/common/strutils.py +++ b/openstack/common/strutils.py @@ -21,6 +21,12 @@ System-level utilities and helper functions. import sys +from 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): """ @@ -37,27 +43,38 @@ def int_from_bool_as_string(subject): return bool_from_string(subject) and 1 or 0 -def bool_from_string(subject): +def bool_from_string(subject, strict=False): """ Interpret a string as a boolean. - Any string value in: - - ('True', 'true', 'On', 'on', 'Yes', 'yes', '1') + 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. - is interpreted as a boolean True. + Useful for JSON-decoded stuff and config file parsing. - 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'. """ - try: - # True or 1 or '1' -> True - # False or < 1 or > 1 or '0' -> False - return int(subject) == 1 - except TypeError: - # None -> False + 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 - except ValueError: - return subject.strip().lower() in ('true', 'on', 'yes') def safe_decode(text, incoming=None, errors='strict'): diff --git a/tests/unit/test_strutils.py b/tests/unit/test_strutils.py index b0af958..bad50c8 100644 --- a/tests/unit/test_strutils.py +++ b/tests/unit/test_strutils.py @@ -1,3 +1,4 @@ +# -*- coding: utf-8 -*- # vim: tabstop=4 shiftwidth=4 softtabstop=4 # Copyright 2011 OpenStack Foundation. @@ -37,6 +38,10 @@ class StrUtilsTest(utils.BaseTestCase): self.assertTrue(strutils.bool_from_string(c('YES'))) self.assertTrue(strutils.bool_from_string(c('yEs'))) self.assertTrue(strutils.bool_from_string(c('1'))) + self.assertTrue(strutils.bool_from_string(c('T'))) + self.assertTrue(strutils.bool_from_string(c('t'))) + self.assertTrue(strutils.bool_from_string(c('Y'))) + self.assertTrue(strutils.bool_from_string(c('y'))) self.assertFalse(strutils.bool_from_string(c('false'))) self.assertFalse(strutils.bool_from_string(c('FALSE'))) @@ -47,9 +52,15 @@ class StrUtilsTest(utils.BaseTestCase): self.assertFalse(strutils.bool_from_string(c('42'))) self.assertFalse(strutils.bool_from_string(c( 'This should not be True'))) + self.assertFalse(strutils.bool_from_string(c('F'))) + self.assertFalse(strutils.bool_from_string(c('f'))) + self.assertFalse(strutils.bool_from_string(c('N'))) + self.assertFalse(strutils.bool_from_string(c('n'))) # Whitespace should be stripped + self.assertTrue(strutils.bool_from_string(c(' 1 '))) self.assertTrue(strutils.bool_from_string(c(' true '))) + self.assertFalse(strutils.bool_from_string(c(' 0 '))) self.assertFalse(strutils.bool_from_string(c(' false '))) def test_bool_from_string(self): @@ -57,6 +68,14 @@ class StrUtilsTest(utils.BaseTestCase): def test_unicode_bool_from_string(self): self._test_bool_from_string(six.text_type) + self.assertFalse(strutils.bool_from_string(u'使用', strict=False)) + + exc = self.assertRaises(ValueError, strutils.bool_from_string, + u'使用', strict=True) + expected_msg = (u"Unrecognized value '使用', acceptable values are:" + u" '0', '1', 'f', 'false', 'n', 'no', 'off', 'on'," + u" 't', 'true', 'y', 'yes'") + self.assertEqual(expected_msg, unicode(exc)) def test_other_bool_from_string(self): self.assertFalse(strutils.bool_from_string(None)) @@ -69,6 +88,48 @@ class StrUtilsTest(utils.BaseTestCase): self.assertFalse(strutils.bool_from_string(0)) self.assertFalse(strutils.bool_from_string(2)) + def test_strict_bool_from_string(self): + # None isn't allowed in strict mode + exc = self.assertRaises(ValueError, strutils.bool_from_string, None, + strict=True) + expected_msg = ("Unrecognized value 'None', acceptable values are:" + " '0', '1', 'f', 'false', 'n', 'no', 'off', 'on'," + " 't', 'true', 'y', 'yes'") + self.assertEqual(expected_msg, str(exc)) + + # Unrecognized strings aren't allowed + self.assertFalse(strutils.bool_from_string('Other', strict=False)) + exc = self.assertRaises(ValueError, strutils.bool_from_string, 'Other', + strict=True) + expected_msg = ("Unrecognized value 'Other', acceptable values are:" + " '0', '1', 'f', 'false', 'n', 'no', 'off', 'on'," + " 't', 'true', 'y', 'yes'") + self.assertEqual(expected_msg, str(exc)) + + # Unrecognized numbers aren't allowed + exc = self.assertRaises(ValueError, strutils.bool_from_string, 2, + strict=True) + expected_msg = ("Unrecognized value '2', acceptable values are:" + " '0', '1', 'f', 'false', 'n', 'no', 'off', 'on'," + " 't', 'true', 'y', 'yes'") + self.assertEqual(expected_msg, str(exc)) + + # False-like values are allowed + self.assertFalse(strutils.bool_from_string('f', strict=True)) + self.assertFalse(strutils.bool_from_string('false', strict=True)) + self.assertFalse(strutils.bool_from_string('off', strict=True)) + self.assertFalse(strutils.bool_from_string('n', strict=True)) + self.assertFalse(strutils.bool_from_string('no', strict=True)) + self.assertFalse(strutils.bool_from_string('0', strict=True)) + + self.assertTrue(strutils.bool_from_string('1', strict=True)) + + # Avoid font-similarity issues (one looks like lowercase-el, zero like + # oh, etc...) + for char in ('O', 'o', 'L', 'l', 'I', 'i'): + self.assertRaises(ValueError, strutils.bool_from_string, char, + strict=True) + def test_int_from_bool_as_string(self): self.assertEqual(1, strutils.int_from_bool_as_string(True)) self.assertEqual(0, strutils.int_from_bool_as_string(False)) |
