You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
381 lines
13 KiB
381 lines
13 KiB
4 years ago
|
# pylint: disable=missing-docstring, too-few-public-methods
|
||
|
"""
|
||
|
Test the trait-type ``UseEnum``.
|
||
|
"""
|
||
|
|
||
|
import unittest
|
||
|
import enum
|
||
|
from traitlets import HasTraits, TraitError, Enum, UseEnum, CaselessStrEnum, FuzzyEnum
|
||
|
|
||
|
|
||
|
# -----------------------------------------------------------------------------
|
||
|
# TEST SUPPORT:
|
||
|
# -----------------------------------------------------------------------------
|
||
|
|
||
|
class Color(enum.Enum):
|
||
|
red = 1
|
||
|
green = 2
|
||
|
blue = 3
|
||
|
yellow = 4
|
||
|
|
||
|
class OtherColor(enum.Enum):
|
||
|
red = 0
|
||
|
green = 1
|
||
|
|
||
|
|
||
|
class CSColor(enum.Enum):
|
||
|
red = 1
|
||
|
Green = 2
|
||
|
BLUE = 3
|
||
|
YeLLoW = 4
|
||
|
|
||
|
|
||
|
color_choices = 'red Green BLUE YeLLoW'.split()
|
||
|
|
||
|
|
||
|
# -----------------------------------------------------------------------------
|
||
|
# TESTSUITE:
|
||
|
# -----------------------------------------------------------------------------
|
||
|
class TestUseEnum(unittest.TestCase):
|
||
|
# pylint: disable=invalid-name
|
||
|
|
||
|
class Example(HasTraits):
|
||
|
color = UseEnum(Color, help="Color enum")
|
||
|
|
||
|
def test_assign_enum_value(self):
|
||
|
example = self.Example()
|
||
|
example.color = Color.green
|
||
|
self.assertEqual(example.color, Color.green)
|
||
|
|
||
|
def test_assign_all_enum_values(self):
|
||
|
# pylint: disable=no-member
|
||
|
enum_values = [value for value in Color.__members__.values()]
|
||
|
for value in enum_values:
|
||
|
self.assertIsInstance(value, Color)
|
||
|
example = self.Example()
|
||
|
example.color = value
|
||
|
self.assertEqual(example.color, value)
|
||
|
self.assertIsInstance(value, Color)
|
||
|
|
||
|
def test_assign_enum_value__with_other_enum_raises_error(self):
|
||
|
example = self.Example()
|
||
|
with self.assertRaises(TraitError):
|
||
|
example.color = OtherColor.green
|
||
|
|
||
|
def test_assign_enum_name_1(self):
|
||
|
# -- CONVERT: string => Enum value (item)
|
||
|
example = self.Example()
|
||
|
example.color = "red"
|
||
|
self.assertEqual(example.color, Color.red)
|
||
|
|
||
|
def test_assign_enum_value_name(self):
|
||
|
# -- CONVERT: string => Enum value (item)
|
||
|
# pylint: disable=no-member
|
||
|
enum_names = [enum_val.name for enum_val in Color.__members__.values()]
|
||
|
for value in enum_names:
|
||
|
self.assertIsInstance(value, str)
|
||
|
example = self.Example()
|
||
|
enum_value = Color.__members__.get(value)
|
||
|
example.color = value
|
||
|
self.assertIs(example.color, enum_value)
|
||
|
self.assertEqual(example.color.name, value)
|
||
|
|
||
|
def test_assign_scoped_enum_value_name(self):
|
||
|
# -- CONVERT: string => Enum value (item)
|
||
|
scoped_names = ["Color.red", "Color.green", "Color.blue", "Color.yellow"]
|
||
|
for value in scoped_names:
|
||
|
example = self.Example()
|
||
|
example.color = value
|
||
|
self.assertIsInstance(example.color, Color)
|
||
|
self.assertEqual(str(example.color), value)
|
||
|
|
||
|
def test_assign_bad_enum_value_name__raises_error(self):
|
||
|
# -- CONVERT: string => Enum value (item)
|
||
|
bad_enum_names = ["UNKNOWN_COLOR", "RED", "Green", "blue2"]
|
||
|
for value in bad_enum_names:
|
||
|
example = self.Example()
|
||
|
with self.assertRaises(TraitError):
|
||
|
example.color = value
|
||
|
|
||
|
def test_assign_enum_value_number_1(self):
|
||
|
# -- CONVERT: number => Enum value (item)
|
||
|
example = self.Example()
|
||
|
example.color = 1 # == Color.red.value
|
||
|
example.color = Color.red.value
|
||
|
self.assertEqual(example.color, Color.red)
|
||
|
|
||
|
def test_assign_enum_value_number(self):
|
||
|
# -- CONVERT: number => Enum value (item)
|
||
|
# pylint: disable=no-member
|
||
|
enum_numbers = [enum_val.value
|
||
|
for enum_val in Color.__members__.values()]
|
||
|
for value in enum_numbers:
|
||
|
self.assertIsInstance(value, int)
|
||
|
example = self.Example()
|
||
|
example.color = value
|
||
|
self.assertIsInstance(example.color, Color)
|
||
|
self.assertEqual(example.color.value, value)
|
||
|
|
||
|
def test_assign_bad_enum_value_number__raises_error(self):
|
||
|
# -- CONVERT: number => Enum value (item)
|
||
|
bad_numbers = [-1, 0, 5]
|
||
|
for value in bad_numbers:
|
||
|
self.assertIsInstance(value, int)
|
||
|
assert UseEnum(Color).select_by_number(value, None) is None
|
||
|
example = self.Example()
|
||
|
with self.assertRaises(TraitError):
|
||
|
example.color = value
|
||
|
|
||
|
def test_ctor_without_default_value(self):
|
||
|
# -- IMPLICIT: default_value = Color.red (first enum-value)
|
||
|
class Example2(HasTraits):
|
||
|
color = UseEnum(Color)
|
||
|
|
||
|
example = Example2()
|
||
|
self.assertEqual(example.color, Color.red)
|
||
|
|
||
|
def test_ctor_with_default_value_as_enum_value(self):
|
||
|
# -- CONVERT: number => Enum value (item)
|
||
|
class Example2(HasTraits):
|
||
|
color = UseEnum(Color, default_value=Color.green)
|
||
|
|
||
|
example = Example2()
|
||
|
self.assertEqual(example.color, Color.green)
|
||
|
|
||
|
|
||
|
def test_ctor_with_default_value_none_and_not_allow_none(self):
|
||
|
# -- IMPLICIT: default_value = Color.red (first enum-value)
|
||
|
class Example2(HasTraits):
|
||
|
color1 = UseEnum(Color, default_value=None, allow_none=False)
|
||
|
color2 = UseEnum(Color, default_value=None)
|
||
|
example = Example2()
|
||
|
self.assertEqual(example.color1, Color.red)
|
||
|
self.assertEqual(example.color2, Color.red)
|
||
|
|
||
|
def test_ctor_with_default_value_none_and_allow_none(self):
|
||
|
class Example2(HasTraits):
|
||
|
color1 = UseEnum(Color, default_value=None, allow_none=True)
|
||
|
color2 = UseEnum(Color, allow_none=True)
|
||
|
|
||
|
example = Example2()
|
||
|
self.assertIs(example.color1, None)
|
||
|
self.assertIs(example.color2, None)
|
||
|
|
||
|
def test_assign_none_without_allow_none_resets_to_default_value(self):
|
||
|
class Example2(HasTraits):
|
||
|
color1 = UseEnum(Color, allow_none=False)
|
||
|
color2 = UseEnum(Color)
|
||
|
|
||
|
example = Example2()
|
||
|
example.color1 = None
|
||
|
example.color2 = None
|
||
|
self.assertIs(example.color1, Color.red)
|
||
|
self.assertIs(example.color2, Color.red)
|
||
|
|
||
|
def test_assign_none_to_enum_or_none(self):
|
||
|
class Example2(HasTraits):
|
||
|
color = UseEnum(Color, allow_none=True)
|
||
|
|
||
|
example = Example2()
|
||
|
example.color = None
|
||
|
self.assertIs(example.color, None)
|
||
|
|
||
|
def test_assign_bad_value_with_to_enum_or_none(self):
|
||
|
class Example2(HasTraits):
|
||
|
color = UseEnum(Color, allow_none=True)
|
||
|
|
||
|
example = Example2()
|
||
|
with self.assertRaises(TraitError):
|
||
|
example.color = "BAD_VALUE"
|
||
|
|
||
|
def test_info(self):
|
||
|
import sys
|
||
|
|
||
|
choices = color_choices
|
||
|
class Example(HasTraits):
|
||
|
enum1 = Enum(choices, allow_none=False)
|
||
|
enum2 = CaselessStrEnum(choices, allow_none=False)
|
||
|
enum3 = FuzzyEnum(choices, allow_none=False)
|
||
|
enum4 = UseEnum(CSColor, allow_none=False)
|
||
|
|
||
|
for i in range(1,5):
|
||
|
attr = 'enum%s' % i
|
||
|
enum = getattr(Example, attr)
|
||
|
|
||
|
enum.allow_none = True
|
||
|
|
||
|
info = enum.info()
|
||
|
self.assertEqual(len(info.split(', ')), len(choices), info.split(', '))
|
||
|
self.assertIn('or None', info)
|
||
|
|
||
|
info = enum.info_rst()
|
||
|
self.assertEqual(len(info.split('|')), len(choices), info.split('|'))
|
||
|
self.assertIn('or `None`', info)
|
||
|
## Check no single `\` exists.
|
||
|
self.assertNotRegex(info, r'\b\\\b')
|
||
|
|
||
|
enum.allow_none = False
|
||
|
|
||
|
info = enum.info()
|
||
|
self.assertEqual(len(info.split(', ')), len(choices), info.split(', '))
|
||
|
self.assertNotIn('None', info)
|
||
|
|
||
|
info = enum.info_rst()
|
||
|
self.assertEqual(len(info.split('|')), len(choices), info.split('|'))
|
||
|
self.assertNotIn('None', info)
|
||
|
## Check no single `\` exists.
|
||
|
self.assertNotRegex(info, r'\b\\\b')
|
||
|
|
||
|
|
||
|
|
||
|
# -----------------------------------------------------------------------------
|
||
|
# TESTSUITE:
|
||
|
# -----------------------------------------------------------------------------
|
||
|
|
||
|
class TestFuzzyEnum(unittest.TestCase):
|
||
|
## Check mostly `validate()`, Ctor must be checked on generic `Enum`
|
||
|
# or `CaselessStrEnum`.
|
||
|
|
||
|
def test_search_all_prefixes__overwrite(self):
|
||
|
class FuzzyExample(HasTraits):
|
||
|
color = FuzzyEnum(color_choices, help="Color enum")
|
||
|
|
||
|
example = FuzzyExample()
|
||
|
for color in color_choices:
|
||
|
for wlen in range(1, len(color)):
|
||
|
value = color[:wlen]
|
||
|
|
||
|
example.color = value
|
||
|
self.assertEqual(example.color, color)
|
||
|
|
||
|
example.color = value.upper()
|
||
|
self.assertEqual(example.color, color)
|
||
|
|
||
|
example.color = value.lower()
|
||
|
self.assertEqual(example.color, color)
|
||
|
|
||
|
def test_search_all_prefixes__ctor(self):
|
||
|
class FuzzyExample(HasTraits):
|
||
|
color = FuzzyEnum(color_choices, help="Color enum")
|
||
|
|
||
|
for color in color_choices:
|
||
|
for wlen in range(1, len(color)):
|
||
|
value = color[:wlen]
|
||
|
|
||
|
example = FuzzyExample()
|
||
|
example.color = value
|
||
|
self.assertEqual(example.color, color)
|
||
|
|
||
|
example = FuzzyExample()
|
||
|
example.color = value.upper()
|
||
|
self.assertEqual(example.color, color)
|
||
|
|
||
|
example = FuzzyExample()
|
||
|
example.color = value.lower()
|
||
|
self.assertEqual(example.color, color)
|
||
|
|
||
|
def test_search_substrings__overwrite(self):
|
||
|
class FuzzyExample(HasTraits):
|
||
|
color = FuzzyEnum(color_choices, help="Color enum",
|
||
|
substring_matching=True)
|
||
|
|
||
|
example = FuzzyExample()
|
||
|
for color in color_choices:
|
||
|
for wlen in range(0, 2):
|
||
|
value = color[wlen:]
|
||
|
|
||
|
example.color = value
|
||
|
self.assertEqual(example.color, color)
|
||
|
|
||
|
example.color = value.upper()
|
||
|
self.assertEqual(example.color, color)
|
||
|
|
||
|
example.color = value.lower()
|
||
|
self.assertEqual(example.color, color)
|
||
|
|
||
|
def test_search_substrings__ctor(self):
|
||
|
class FuzzyExample(HasTraits):
|
||
|
color = FuzzyEnum(color_choices, help="Color enum",
|
||
|
substring_matching=True)
|
||
|
|
||
|
color = color_choices[-1] # 'YeLLoW'
|
||
|
for end in (-1, len(color)):
|
||
|
for start in range(1, len(color) - 2):
|
||
|
value = color[start:end]
|
||
|
|
||
|
example = FuzzyExample()
|
||
|
example.color = value
|
||
|
self.assertEqual(example.color, color)
|
||
|
|
||
|
example = FuzzyExample()
|
||
|
example.color = value.upper()
|
||
|
self.assertEqual(example.color, color)
|
||
|
|
||
|
def test_assign_other_raises(self):
|
||
|
def new_trait_class(case_sensitive, substring_matching):
|
||
|
class Example(HasTraits):
|
||
|
color = FuzzyEnum(color_choices,
|
||
|
case_sensitive=case_sensitive,
|
||
|
substring_matching=substring_matching)
|
||
|
|
||
|
return Example
|
||
|
|
||
|
example = new_trait_class(case_sensitive=False, substring_matching=False)()
|
||
|
with self.assertRaises(TraitError):
|
||
|
example.color = ''
|
||
|
with self.assertRaises(TraitError):
|
||
|
example.color = 'BAD COLOR'
|
||
|
with self.assertRaises(TraitError):
|
||
|
example.color = 'ed'
|
||
|
|
||
|
example = new_trait_class(case_sensitive=True, substring_matching=False)()
|
||
|
with self.assertRaises(TraitError):
|
||
|
example.color = ''
|
||
|
with self.assertRaises(TraitError):
|
||
|
example.color = 'Red' # not 'red'
|
||
|
|
||
|
example = new_trait_class(case_sensitive=True, substring_matching=True)()
|
||
|
with self.assertRaises(TraitError):
|
||
|
example.color = ''
|
||
|
with self.assertRaises(TraitError):
|
||
|
example.color = 'BAD COLOR'
|
||
|
with self.assertRaises(TraitError):
|
||
|
example.color = 'green' # not 'Green'
|
||
|
with self.assertRaises(TraitError):
|
||
|
example.color = 'lue' # not (b)'LUE'
|
||
|
with self.assertRaises(TraitError):
|
||
|
example.color = 'lUE' # not (b)'LUE'
|
||
|
|
||
|
example = new_trait_class(case_sensitive=False, substring_matching=True)()
|
||
|
with self.assertRaises(TraitError):
|
||
|
example.color = ''
|
||
|
with self.assertRaises(TraitError):
|
||
|
example.color = 'BAD COLOR'
|
||
|
|
||
|
def test_ctor_with_default_value(self):
|
||
|
def new_trait_class(default_value,
|
||
|
case_sensitive, substring_matching):
|
||
|
class Example(HasTraits):
|
||
|
color = FuzzyEnum(color_choices,
|
||
|
default_value=default_value,
|
||
|
case_sensitive=case_sensitive,
|
||
|
substring_matching=substring_matching)
|
||
|
|
||
|
return Example
|
||
|
|
||
|
for color in color_choices:
|
||
|
example = new_trait_class(color, False, False)()
|
||
|
self.assertEqual(example.color, color)
|
||
|
|
||
|
example = new_trait_class(color.upper(), False, False)()
|
||
|
self.assertEqual(example.color, color)
|
||
|
|
||
|
color = color_choices[-1] # 'YeLLoW'
|
||
|
example = new_trait_class(color, True, False)()
|
||
|
self.assertEqual(example.color, color)
|
||
|
|
||
|
## FIXME: default value not validated!
|
||
|
#with self.assertRaises(TraitError):
|
||
|
# example = new_trait_class(color.lower(), True, False)
|
||
|
|