Merge "Add Range type"
This commit is contained in:
commit
9c6775ad08
|
@ -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()
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Reference in New Issue