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