Merge "Add Range type"

This commit is contained in:
Jenkins 2016-08-25 10:10:18 +00:00 committed by Gerrit Code Review
commit 9c6775ad08
2 changed files with 97 additions and 0 deletions

View File

@ -16,6 +16,7 @@ import re
import unittest
from oslo_config import types
from six.moves import range as compat_range
class ConfigTypeTests(unittest.TestCase):
@ -542,6 +543,45 @@ class ListTypeTests(TypeTestHelper, unittest.TestCase):
self.assertFalse(types.List() == types.Integer())
class RangeTypeTests(TypeTestHelper, unittest.TestCase):
type = types.Range()
def assertRange(self, s, r1, r2, step=1):
self.assertEqual(list(compat_range(r1, r2, step)),
list(self.type_instance(s)))
def test_range(self):
self.assertRange('0-2', 0, 3)
self.assertRange('-2-0', -2, 1)
self.assertRange('2-0', 2, -1, -1)
self.assertRange('-3--1', -3, 0)
self.assertRange('-1--3', -1, -4, -1)
self.assertRange('-1', -1, 0)
self.assertInvalid('--1')
self.assertInvalid('4-')
self.assertInvalid('--')
self.assertInvalid('1.1-1.2')
self.assertInvalid('a-b')
def test_range_bounds(self):
self.type_instance = types.Range(1, 3)
self.assertRange('1-3', 1, 4)
self.assertRange('2-2', 2, 3)
self.assertRange('2', 2, 3)
self.assertInvalid('1-4')
self.assertInvalid('0-3')
self.assertInvalid('0-4')
def test_range_exclusive(self):
self.type_instance = types.Range(inclusive=False)
self.assertRange('0-2', 0, 2)
self.assertRange('-2-0', -2, 0)
self.assertRange('2-0', 2, 0, -1)
self.assertRange('-3--1', -3, -1)
self.assertRange('-1--3', -1, -3, -1)
self.assertRange('-1', -1, -1)
class DictTypeTests(TypeTestHelper, unittest.TestCase):
type = types.Dict()

View File

@ -27,6 +27,7 @@ import abc
import netaddr
import rfc3986
import six
from six.moves import range as compat_range
@six.add_metaclass(abc.ABCMeta)
@ -490,6 +491,62 @@ class List(ConfigType):
return ','.join(value)
class Range(ConfigType):
"""Range type.
Represents a range of integers. A range is identified by an integer both
sides of a '-' character. Negatives are allowed. A single number is also a
valid range.
:param min: Optional check that lower bound is greater than or equal to
min.
:param max: Optional check that upper bound is less than or equal to max.
:param inclusive: True if the right bound is to be included in the range.
:param type_name: Type name to be used in the sample config file.
.. versionadded:: 3.16
"""
def __init__(self, min=None, max=None, inclusive=True,
type_name='range value'):
super(Range, self).__init__(type_name)
self.min = min
self.max = max
self.inclusive = inclusive
def __call__(self, value):
value = str(value)
num = "0|-?[1-9][0-9]*"
m = re.match("^(%s)(?:-(%s))?$" % (num, num), value)
if not m:
raise ValueError('Invalid Range: %s' % value)
left = int(m.group(1))
right = int(left if m.group(2) is None else m.group(2))
if left < right:
left = Integer(min=self.min)(left)
right = Integer(max=self.max)(right)
step = 1
else:
left = Integer(max=self.max)(left)
right = Integer(min=self.min)(right)
step = -1
if self.inclusive:
right += step
return compat_range(left, right, step)
def __eq__(self, other):
return (
(self.__class__ == other.__class__) and
(self.min == other.min) and
(self.max == other.max)
)
def _formatter(self, value):
return value
class Dict(ConfigType):
"""Dictionary type.