Show More
@@ -673,6 +673,23 b' class TraitTestBase(TestCase):' | |||||
673 | if hasattr(self, '_default_value'): |
|
673 | if hasattr(self, '_default_value'): | |
674 | self.assertEqual(self._default_value, self.obj.value) |
|
674 | self.assertEqual(self._default_value, self.obj.value) | |
675 |
|
675 | |||
|
676 | def test_allow_none(self): | |||
|
677 | if (hasattr(self, '_bad_values') and hasattr(self, '_good_values') and | |||
|
678 | None in self._bad_values): | |||
|
679 | trait=self.obj.traits()['value'] | |||
|
680 | try: | |||
|
681 | trait.allow_none = True | |||
|
682 | self._bad_values.remove(None) | |||
|
683 | #skip coerce. Allow None casts None to None. | |||
|
684 | self.assign(None) | |||
|
685 | self.assertEqual(self.obj.value,None) | |||
|
686 | self.test_good_values() | |||
|
687 | self.test_bad_values() | |||
|
688 | finally: | |||
|
689 | #tear down | |||
|
690 | trait.allow_none = False | |||
|
691 | self._bad_values.append(None) | |||
|
692 | ||||
676 | def tearDown(self): |
|
693 | def tearDown(self): | |
677 | # restore default value after tests, if set |
|
694 | # restore default value after tests, if set | |
678 | if hasattr(self, '_default_value'): |
|
695 | if hasattr(self, '_default_value'): | |
@@ -830,7 +847,7 b' class TestObjectName(TraitTestBase):' | |||||
830 | _default_value = "abc" |
|
847 | _default_value = "abc" | |
831 | _good_values = ["a", "gh", "g9", "g_", "_G", u"a345_"] |
|
848 | _good_values = ["a", "gh", "g9", "g_", "_G", u"a345_"] | |
832 | _bad_values = [1, "", u"β¬", "9g", "!", "#abc", "aj@", "a.b", "a()", "a[0]", |
|
849 | _bad_values = [1, "", u"β¬", "9g", "!", "#abc", "aj@", "a.b", "a()", "a[0]", | |
833 |
|
|
850 | None, object(), object] | |
834 | if sys.version_info[0] < 3: |
|
851 | if sys.version_info[0] < 3: | |
835 | _bad_values.append(u"ΓΎ") |
|
852 | _bad_values.append(u"ΓΎ") | |
836 | else: |
|
853 | else: | |
@@ -845,7 +862,7 b' class TestDottedObjectName(TraitTestBase):' | |||||
845 |
|
862 | |||
846 | _default_value = "a.b" |
|
863 | _default_value = "a.b" | |
847 | _good_values = ["A", "y.t", "y765.__repr__", "os.path.join", u"os.path.join"] |
|
864 | _good_values = ["A", "y.t", "y765.__repr__", "os.path.join", u"os.path.join"] | |
848 | _bad_values = [1, u"abc.β¬", "_.@", ".", ".abc", "abc.", ".abc."] |
|
865 | _bad_values = [1, u"abc.β¬", "_.@", ".", ".abc", "abc.", ".abc.", None] | |
849 | if sys.version_info[0] < 3: |
|
866 | if sys.version_info[0] < 3: | |
850 | _bad_values.append(u"t.ΓΎ") |
|
867 | _bad_values.append(u"t.ΓΎ") | |
851 | else: |
|
868 | else: | |
@@ -862,7 +879,7 b' class TestTCPAddress(TraitTestBase):' | |||||
862 |
|
879 | |||
863 | _default_value = ('127.0.0.1',0) |
|
880 | _default_value = ('127.0.0.1',0) | |
864 | _good_values = [('localhost',0),('192.168.0.1',1000),('www.google.com',80)] |
|
881 | _good_values = [('localhost',0),('192.168.0.1',1000),('www.google.com',80)] | |
865 | _bad_values = [(0,0),('localhost',10.0),('localhost',-1)] |
|
882 | _bad_values = [(0,0),('localhost',10.0),('localhost',-1), None] | |
866 |
|
883 | |||
867 | class ListTrait(HasTraits): |
|
884 | class ListTrait(HasTraits): | |
868 |
|
885 | |||
@@ -919,14 +936,14 b' class TestLenList(TraitTestBase):' | |||||
919 |
|
936 | |||
920 | class TupleTrait(HasTraits): |
|
937 | class TupleTrait(HasTraits): | |
921 |
|
938 | |||
922 | value = Tuple(Int) |
|
939 | value = Tuple(Int(allow_none=True)) | |
923 |
|
940 | |||
924 | class TestTupleTrait(TraitTestBase): |
|
941 | class TestTupleTrait(TraitTestBase): | |
925 |
|
942 | |||
926 | obj = TupleTrait() |
|
943 | obj = TupleTrait() | |
927 |
|
944 | |||
928 | _default_value = None |
|
945 | _default_value = None | |
929 | _good_values = [(1,), None, (0,), [1]] |
|
946 | _good_values = [(1,), None, (0,), [1], (None,)] | |
930 | _bad_values = [10, (1,2), ('a'), ()] |
|
947 | _bad_values = [10, (1,2), ('a'), ()] | |
931 |
|
948 | |||
932 | def coerce(self, value): |
|
949 | def coerce(self, value): |
@@ -252,13 +252,16 b' class TraitType(object):' | |||||
252 |
|
252 | |||
253 | metadata = {} |
|
253 | metadata = {} | |
254 | default_value = Undefined |
|
254 | default_value = Undefined | |
|
255 | allow_none = False | |||
255 | info_text = 'any value' |
|
256 | info_text = 'any value' | |
256 |
|
257 | |||
257 | def __init__(self, default_value=NoDefaultSpecified, **metadata): |
|
258 | def __init__(self, default_value=NoDefaultSpecified, allow_none=None, **metadata): | |
258 | """Create a TraitType. |
|
259 | """Create a TraitType. | |
259 | """ |
|
260 | """ | |
260 | if default_value is not NoDefaultSpecified: |
|
261 | if default_value is not NoDefaultSpecified: | |
261 | self.default_value = default_value |
|
262 | self.default_value = default_value | |
|
263 | if allow_none is not None: | |||
|
264 | self.allow_none = allow_none | |||
262 |
|
265 | |||
263 | if len(metadata) > 0: |
|
266 | if len(metadata) > 0: | |
264 | if len(self.metadata) > 0: |
|
267 | if len(self.metadata) > 0: | |
@@ -371,6 +374,8 b' class TraitType(object):' | |||||
371 | obj._notify_trait(self.name, old_value, new_value) |
|
374 | obj._notify_trait(self.name, old_value, new_value) | |
372 |
|
375 | |||
373 | def _validate(self, obj, value): |
|
376 | def _validate(self, obj, value): | |
|
377 | if value is None and self.allow_none: | |||
|
378 | return value | |||
374 | if hasattr(self, 'validate'): |
|
379 | if hasattr(self, 'validate'): | |
375 | return self.validate(obj, value) |
|
380 | return self.validate(obj, value) | |
376 | elif hasattr(self, 'is_valid_for'): |
|
381 | elif hasattr(self, 'is_valid_for'): | |
@@ -745,9 +750,8 b' class Type(ClassBasedTraitType):' | |||||
745 | raise TraitError("A Type trait must specify a class.") |
|
750 | raise TraitError("A Type trait must specify a class.") | |
746 |
|
751 | |||
747 | self.klass = klass |
|
752 | self.klass = klass | |
748 | self._allow_none = allow_none |
|
|||
749 |
|
753 | |||
750 | super(Type, self).__init__(default_value, **metadata) |
|
754 | super(Type, self).__init__(default_value, allow_none=allow_none, **metadata) | |
751 |
|
755 | |||
752 | def validate(self, obj, value): |
|
756 | def validate(self, obj, value): | |
753 | """Validates that the value is a valid object instance.""" |
|
757 | """Validates that the value is a valid object instance.""" | |
@@ -755,8 +759,7 b' class Type(ClassBasedTraitType):' | |||||
755 | if issubclass(value, self.klass): |
|
759 | if issubclass(value, self.klass): | |
756 | return value |
|
760 | return value | |
757 | except: |
|
761 | except: | |
758 | if (value is None) and (self._allow_none): |
|
762 | pass | |
759 | return value |
|
|||
760 |
|
763 | |||
761 | self.error(obj, value) |
|
764 | self.error(obj, value) | |
762 |
|
765 | |||
@@ -767,7 +770,7 b' class Type(ClassBasedTraitType):' | |||||
767 | else: |
|
770 | else: | |
768 | klass = self.klass.__name__ |
|
771 | klass = self.klass.__name__ | |
769 | result = 'a subclass of ' + klass |
|
772 | result = 'a subclass of ' + klass | |
770 |
if self. |
|
773 | if self.allow_none: | |
771 | return result + ' or None' |
|
774 | return result + ' or None' | |
772 | return result |
|
775 | return result | |
773 |
|
776 | |||
@@ -831,8 +834,6 b' class Instance(ClassBasedTraitType):' | |||||
831 | not (but not both), None is replace by ``()`` or ``{}``. |
|
834 | not (but not both), None is replace by ``()`` or ``{}``. | |
832 | """ |
|
835 | """ | |
833 |
|
836 | |||
834 | self._allow_none = allow_none |
|
|||
835 |
|
||||
836 | if (klass is None) or (not (inspect.isclass(klass) or isinstance(klass, py3compat.string_types))): |
|
837 | if (klass is None) or (not (inspect.isclass(klass) or isinstance(klass, py3compat.string_types))): | |
837 | raise TraitError('The klass argument must be a class' |
|
838 | raise TraitError('The klass argument must be a class' | |
838 | ' you gave: %r' % klass) |
|
839 | ' you gave: %r' % klass) | |
@@ -856,14 +857,9 b' class Instance(ClassBasedTraitType):' | |||||
856 |
|
857 | |||
857 | default_value = DefaultValueGenerator(*args, **kw) |
|
858 | default_value = DefaultValueGenerator(*args, **kw) | |
858 |
|
859 | |||
859 | super(Instance, self).__init__(default_value, **metadata) |
|
860 | super(Instance, self).__init__(default_value, allow_none=allow_none, **metadata) | |
860 |
|
861 | |||
861 | def validate(self, obj, value): |
|
862 | def validate(self, obj, value): | |
862 | if value is None: |
|
|||
863 | if self._allow_none: |
|
|||
864 | return value |
|
|||
865 | self.error(obj, value) |
|
|||
866 |
|
||||
867 | if isinstance(value, self.klass): |
|
863 | if isinstance(value, self.klass): | |
868 | return value |
|
864 | return value | |
869 | else: |
|
865 | else: | |
@@ -875,7 +871,7 b' class Instance(ClassBasedTraitType):' | |||||
875 | else: |
|
871 | else: | |
876 | klass = self.klass.__name__ |
|
872 | klass = self.klass.__name__ | |
877 | result = class_of(klass) |
|
873 | result = class_of(klass) | |
878 |
if self. |
|
874 | if self.allow_none: | |
879 | return result + ' or None' |
|
875 | return result + ' or None' | |
880 |
|
876 | |||
881 | return result |
|
877 | return result | |
@@ -1169,14 +1165,9 b' class Enum(TraitType):' | |||||
1169 |
|
1165 | |||
1170 | def __init__(self, values, default_value=None, allow_none=True, **metadata): |
|
1166 | def __init__(self, values, default_value=None, allow_none=True, **metadata): | |
1171 | self.values = values |
|
1167 | self.values = values | |
1172 | self._allow_none = allow_none |
|
1168 | super(Enum, self).__init__(default_value, allow_none=allow_none, **metadata) | |
1173 | super(Enum, self).__init__(default_value, **metadata) |
|
|||
1174 |
|
1169 | |||
1175 | def validate(self, obj, value): |
|
1170 | def validate(self, obj, value): | |
1176 | if value is None: |
|
|||
1177 | if self._allow_none: |
|
|||
1178 | return value |
|
|||
1179 |
|
||||
1180 | if value in self.values: |
|
1171 | if value in self.values: | |
1181 | return value |
|
1172 | return value | |
1182 | self.error(obj, value) |
|
1173 | self.error(obj, value) | |
@@ -1184,7 +1175,7 b' class Enum(TraitType):' | |||||
1184 | def info(self): |
|
1175 | def info(self): | |
1185 | """ Returns a description of the trait.""" |
|
1176 | """ Returns a description of the trait.""" | |
1186 | result = 'any of ' + repr(self.values) |
|
1177 | result = 'any of ' + repr(self.values) | |
1187 |
if self. |
|
1178 | if self.allow_none: | |
1188 | return result + ' or None' |
|
1179 | return result + ' or None' | |
1189 | return result |
|
1180 | return result | |
1190 |
|
1181 | |||
@@ -1192,10 +1183,6 b' class CaselessStrEnum(Enum):' | |||||
1192 | """An enum of strings that are caseless in validate.""" |
|
1183 | """An enum of strings that are caseless in validate.""" | |
1193 |
|
1184 | |||
1194 | def validate(self, obj, value): |
|
1185 | def validate(self, obj, value): | |
1195 | if value is None: |
|
|||
1196 | if self._allow_none: |
|
|||
1197 | return value |
|
|||
1198 |
|
||||
1199 | if not isinstance(value, py3compat.string_types): |
|
1186 | if not isinstance(value, py3compat.string_types): | |
1200 | self.error(obj, value) |
|
1187 | self.error(obj, value) | |
1201 |
|
1188 | |||
@@ -1290,7 +1277,7 b' class Container(Instance):' | |||||
1290 | return value |
|
1277 | return value | |
1291 | for v in value: |
|
1278 | for v in value: | |
1292 | try: |
|
1279 | try: | |
1293 | v = self._trait.validate(obj, v) |
|
1280 | v = self._trait._validate(obj, v) | |
1294 | except TraitError: |
|
1281 | except TraitError: | |
1295 | self.element_error(obj, v, self._trait) |
|
1282 | self.element_error(obj, v, self._trait) | |
1296 | else: |
|
1283 | else: | |
@@ -1366,8 +1353,6 b' class List(Container):' | |||||
1366 |
|
1353 | |||
1367 | def validate(self, obj, value): |
|
1354 | def validate(self, obj, value): | |
1368 | value = super(List, self).validate(obj, value) |
|
1355 | value = super(List, self).validate(obj, value) | |
1369 | if value is None: |
|
|||
1370 | return value |
|
|||
1371 |
|
1356 | |||
1372 | value = self.validate_elements(obj, value) |
|
1357 | value = self.validate_elements(obj, value) | |
1373 |
|
1358 | |||
@@ -1463,7 +1448,7 b' class Tuple(Container):' | |||||
1463 | validated = [] |
|
1448 | validated = [] | |
1464 | for t,v in zip(self._traits, value): |
|
1449 | for t,v in zip(self._traits, value): | |
1465 | try: |
|
1450 | try: | |
1466 | v = t.validate(obj, v) |
|
1451 | v = t._validate(obj, v) | |
1467 | except TraitError: |
|
1452 | except TraitError: | |
1468 | self.element_error(obj, v, t) |
|
1453 | self.element_error(obj, v, t) | |
1469 | else: |
|
1454 | else: |
General Comments 0
You need to be logged in to leave comments.
Login now