##// END OF EJS Templates
Implementation in TraitType directly.
zah -
Show More
@@ -16,7 +16,7 b' import nose.tools as nt'
16 16 from nose import SkipTest
17 17
18 18 from IPython.utils.traitlets import (
19 HasTraits, MetaHasTraits, TraitType, AllowNone, Any, CBytes, Dict,
19 HasTraits, MetaHasTraits, TraitType, Any, CBytes, Dict,
20 20 Int, Long, Integer, Float, Complex, Bytes, Unicode, TraitError,
21 21 Undefined, Type, This, Instance, TCPAddress, List, Tuple,
22 22 ObjectName, DottedObjectName, CRegExp, link
@@ -73,7 +73,7 b' class TestTraitType(TestCase):'
73 73 self.assertEqual(a.tt, -1)
74 74
75 75 def test_default_validate(self):
76 class MyIntTT(AllowNone):
76 class MyIntTT(TraitType):
77 77 def validate(self, obj, value):
78 78 if isinstance(value, int):
79 79 return value
@@ -354,29 +354,29 b' class TestHasTraitsNotify(TestCase):'
354 354
355 355 class A(HasTraits):
356 356 listen_to = ['a']
357
357
358 358 a = Int(0)
359 359 b = 0
360
360
361 361 def __init__(self, **kwargs):
362 362 super(A, self).__init__(**kwargs)
363 363 self.on_trait_change(self.listener1, ['a'])
364
364
365 365 def listener1(self, name, old, new):
366 366 self.b += 1
367 367
368 368 class B(A):
369
369
370 370 c = 0
371 371 d = 0
372
372
373 373 def __init__(self, **kwargs):
374 374 super(B, self).__init__(**kwargs)
375 375 self.on_trait_change(self.listener2)
376
376
377 377 def listener2(self, name, old, new):
378 378 self.c += 1
379
379
380 380 def _a_changed(self, name, old, new):
381 381 self.d += 1
382 382
@@ -442,7 +442,7 b' class TestHasTraits(TestCase):'
442 442 def __init__(self, i):
443 443 super(A, self).__init__()
444 444 self.i = i
445
445
446 446 a = A(5)
447 447 self.assertEqual(a.i, 5)
448 448 # should raise TypeError if no positional arg given
@@ -677,19 +677,19 b' class TraitTestBase(TestCase):'
677 677 if (hasattr(self, '_bad_values') and hasattr(self, '_good_values') and
678 678 None in self._bad_values):
679 679 trait=self.obj.traits()['value']
680 if isinstance(trait, AllowNone) and not trait._allow_none:
681 try:
682 trait._allow_none = True
683 self._bad_values.remove(None)
684 #skip coerce. Allow None casts None to None.
685 self.assign(None)
686 self.assertEqual(self.obj.value,None)
687 self.test_good_values()
688 self.test_bad_values()
689 finally:
690 #tear down
691 trait._allow_none = False
692 self._bad_values.append(None)
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 print "bad values %s" % self
693 693
694 694
695 695 def tearDown(self):
@@ -894,7 +894,7 b' class TestList(TraitTestBase):'
894 894 _default_value = []
895 895 _good_values = [[], [1], list(range(10)), (1,2)]
896 896 _bad_values = [10, [1,'a'], 'a']
897
897
898 898 def coerce(self, value):
899 899 if value is not None:
900 900 value = list(value)
@@ -1073,7 +1073,7 b' class TestLink(TestCase):'
1073 1073 count = Int()
1074 1074 a = A(value=9)
1075 1075 b = B(count=8)
1076
1076
1077 1077 # Register callbacks that count.
1078 1078 callback_count = []
1079 1079 def a_callback(name, old, new):
@@ -1124,4 +1124,4 b' def test_pickle_hastraits():'
1124 1124 c2 = pickle.loads(p)
1125 1125 nt.assert_equal(c2.i, c.i)
1126 1126 nt.assert_equal(c2.j, c.j)
1127
1127 No newline at end of file
@@ -220,7 +220,7 b' class link(object):'
220 220 for obj,attr in self.objects.keys():
221 221 if obj is not sending_obj or attr != sending_attr:
222 222 setattr(obj, attr, new)
223
223
224 224 def unlink(self):
225 225 for key, callback in self.objects.items():
226 226 (obj,attr) = key
@@ -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'):
@@ -677,29 +682,16 b' class HasTraits(py3compat.with_metaclass(MetaHasTraits, object)):'
677 682 else:
678 683 return trait.get_metadata(key)
679 684
680 class AllowNone(TraitType):
681 """A trait that can be set to allow None values. It does not provide
682 validation."""
683 def __init__(self, default_value=NoDefaultSpecified, allow_none = False, **metadata):
684 self._allow_none = allow_none
685 super(AllowNone, self).__init__(default_value, **metadata)
686
687 def _none_ok(self, value):
688 """The validate method can return the None value."""
689 return value is None and self._allow_none
690
691
692 685 #-----------------------------------------------------------------------------
693 686 # Actual TraitTypes implementations/subclasses
694 687 #-----------------------------------------------------------------------------
695 688
696
697 689 #-----------------------------------------------------------------------------
698 690 # TraitTypes subclasses for handling classes and instances of classes
699 691 #-----------------------------------------------------------------------------
700 692
701 693
702 class ClassBasedTraitType(AllowNone):
694 class ClassBasedTraitType(TraitType):
703 695 """A trait with error reporting for Type, Instance and This."""
704 696
705 697 def error(self, obj, value):
@@ -767,8 +759,7 b' class Type(ClassBasedTraitType):'
767 759 if issubclass(value, self.klass):
768 760 return value
769 761 except:
770 if self._none_ok(value):
771 return value
762 pass
772 763
773 764 self.error(obj, value)
774 765
@@ -779,7 +770,7 b' class Type(ClassBasedTraitType):'
779 770 else:
780 771 klass = self.klass.__name__
781 772 result = 'a subclass of ' + klass
782 if self._allow_none:
773 if self.allow_none:
783 774 return result + ' or None'
784 775 return result
785 776
@@ -869,11 +860,6 b' class Instance(ClassBasedTraitType):'
869 860 super(Instance, self).__init__(default_value, allow_none, **metadata)
870 861
871 862 def validate(self, obj, value):
872 if value is None:
873 if self._allow_none:
874 return value
875 self.error(obj, value)
876
877 863 if isinstance(value, self.klass):
878 864 return value
879 865 else:
@@ -885,7 +871,7 b' class Instance(ClassBasedTraitType):'
885 871 else:
886 872 klass = self.klass.__name__
887 873 result = class_of(klass)
888 if self._allow_none:
874 if self.allow_none:
889 875 return result + ' or None'
890 876
891 877 return result
@@ -945,14 +931,14 b' class Any(TraitType):'
945 931 info_text = 'any value'
946 932
947 933
948 class Int(AllowNone):
934 class Int(TraitType):
949 935 """An int trait."""
950 936
951 937 default_value = 0
952 938 info_text = 'an int'
953 939
954 940 def validate(self, obj, value):
955 if isinstance(value, int) or self._none_ok(value):
941 if isinstance(value, int):
956 942 return value
957 943 self.error(obj, value)
958 944
@@ -963,22 +949,20 b' class CInt(Int):'
963 949 try:
964 950 return int(value)
965 951 except:
966 if self._none_ok(value):
967 return value
968 952 self.error(obj, value)
969 953
970 954 if py3compat.PY3:
971 955 Long, CLong = Int, CInt
972 956 Integer = Int
973 957 else:
974 class Long(AllowNone):
958 class Long(TraitType):
975 959 """A long integer trait."""
976 960
977 961 default_value = 0
978 962 info_text = 'a long'
979 963
980 964 def validate(self, obj, value):
981 if isinstance(value, long) or self._none_ok(value):
965 if isinstance(value, long):
982 966 return value
983 967 if isinstance(value, int):
984 968 return long(value)
@@ -992,11 +976,9 b' else:'
992 976 try:
993 977 return long(value)
994 978 except:
995 if self._none_ok(value):
996 return value
997 979 self.error(obj, value)
998 980
999 class Integer(AllowNone):
981 class Integer(TraitType):
1000 982 """An integer trait.
1001 983
1002 984 Longs that are unnecessary (<= sys.maxint) are cast to ints."""
@@ -1005,7 +987,7 b' else:'
1005 987 info_text = 'an integer'
1006 988
1007 989 def validate(self, obj, value):
1008 if isinstance(value, int) or self._none_ok(value):
990 if isinstance(value, int):
1009 991 return value
1010 992 if isinstance(value, long):
1011 993 # downcast longs that fit in int:
@@ -1019,14 +1001,14 b' else:'
1019 1001 self.error(obj, value)
1020 1002
1021 1003
1022 class Float(AllowNone):
1004 class Float(TraitType):
1023 1005 """A float trait."""
1024 1006
1025 1007 default_value = 0.0
1026 1008 info_text = 'a float'
1027 1009
1028 1010 def validate(self, obj, value):
1029 if isinstance(value, float ) or self._none_ok(value):
1011 if isinstance(value, float):
1030 1012 return value
1031 1013 if isinstance(value, int):
1032 1014 return float(value)
@@ -1040,18 +1022,16 b' class CFloat(Float):'
1040 1022 try:
1041 1023 return float(value)
1042 1024 except:
1043 if self._none_ok(value):
1044 return value
1045 1025 self.error(obj, value)
1046 1026
1047 class Complex(AllowNone):
1027 class Complex(TraitType):
1048 1028 """A trait for complex numbers."""
1049 1029
1050 1030 default_value = 0.0 + 0.0j
1051 1031 info_text = 'a complex number'
1052 1032
1053 1033 def validate(self, obj, value):
1054 if isinstance(value, complex) or self._none_ok(value):
1034 if isinstance(value, complex):
1055 1035 return value
1056 1036 if isinstance(value, (float, int)):
1057 1037 return complex(value)
@@ -1065,21 +1045,19 b' class CComplex(Complex):'
1065 1045 try:
1066 1046 return complex(value)
1067 1047 except:
1068 if self._noe_ok(value):
1069 return value
1070 1048 self.error(obj, value)
1071 1049
1072 1050 # We should always be explicit about whether we're using bytes or unicode, both
1073 1051 # for Python 3 conversion and for reliable unicode behaviour on Python 2. So
1074 1052 # we don't have a Str type.
1075 class Bytes(AllowNone):
1053 class Bytes(TraitType):
1076 1054 """A trait for byte strings."""
1077 1055
1078 1056 default_value = b''
1079 1057 info_text = 'a bytes object'
1080 1058
1081 1059 def validate(self, obj, value):
1082 if isinstance(value, bytes) or self._none_ok(value):
1060 if isinstance(value, bytes):
1083 1061 return value
1084 1062 self.error(obj, value)
1085 1063
@@ -1091,19 +1069,17 b' class CBytes(Bytes):'
1091 1069 try:
1092 1070 return bytes(value)
1093 1071 except:
1094 if self._none_ok(value):
1095 return value
1096 1072 self.error(obj, value)
1097 1073
1098 1074
1099 class Unicode(AllowNone):
1075 class Unicode(TraitType):
1100 1076 """A trait for unicode strings."""
1101 1077
1102 1078 default_value = u''
1103 1079 info_text = 'a unicode string'
1104 1080
1105 1081 def validate(self, obj, value):
1106 if isinstance(value, py3compat.unicode_type) or self._none_ok(value):
1082 if isinstance(value, py3compat.unicode_type):
1107 1083 return value
1108 1084 if isinstance(value, bytes):
1109 1085 try:
@@ -1121,12 +1097,10 b' class CUnicode(Unicode):'
1121 1097 try:
1122 1098 return py3compat.unicode_type(value)
1123 1099 except:
1124 if self._allow_none(value):
1125 return value
1126 1100 self.error(obj, value)
1127 1101
1128 1102
1129 class ObjectName(AllowNone):
1103 class ObjectName(TraitType):
1130 1104 """A string holding a valid object name in this version of Python.
1131 1105
1132 1106 This does not check that the name exists in any scope."""
@@ -1148,8 +1122,6 b' class ObjectName(AllowNone):'
1148 1122 return value
1149 1123
1150 1124 def validate(self, obj, value):
1151 if self._none_ok(value):
1152 return value
1153 1125 value = self.coerce_str(obj, value)
1154 1126
1155 1127 if isinstance(value, str) and py3compat.isidentifier(value):
@@ -1159,8 +1131,6 b' class ObjectName(AllowNone):'
1159 1131 class DottedObjectName(ObjectName):
1160 1132 """A string holding a valid dotted object name in Python, such as A.b3._c"""
1161 1133 def validate(self, obj, value):
1162 if self._none_ok(value):
1163 return value
1164 1134 value = self.coerce_str(obj, value)
1165 1135
1166 1136 if isinstance(value, str) and py3compat.isidentifier(value, dotted=True):
@@ -1168,14 +1138,14 b' class DottedObjectName(ObjectName):'
1168 1138 self.error(obj, value)
1169 1139
1170 1140
1171 class Bool(AllowNone):
1141 class Bool(TraitType):
1172 1142 """A boolean (True, False) trait."""
1173 1143
1174 1144 default_value = False
1175 1145 info_text = 'a boolean'
1176 1146
1177 1147 def validate(self, obj, value):
1178 if isinstance(value, bool) or self._none_ok(value):
1148 if isinstance(value, bool):
1179 1149 return value
1180 1150 self.error(obj, value)
1181 1151
@@ -1195,14 +1165,9 b' class Enum(TraitType):'
1195 1165
1196 1166 def __init__(self, values, default_value=None, allow_none=True, **metadata):
1197 1167 self.values = values
1198 self._allow_none = allow_none
1199 super(Enum, self).__init__(default_value, **metadata)
1168 super(Enum, self).__init__(default_value, allow_none, **metadata)
1200 1169
1201 1170 def validate(self, obj, value):
1202 if value is None:
1203 if self._allow_none:
1204 return value
1205
1206 1171 if value in self.values:
1207 1172 return value
1208 1173 self.error(obj, value)
@@ -1210,7 +1175,7 b' class Enum(TraitType):'
1210 1175 def info(self):
1211 1176 """ Returns a description of the trait."""
1212 1177 result = 'any of ' + repr(self.values)
1213 if self._allow_none:
1178 if self.allow_none:
1214 1179 return result + ' or None'
1215 1180 return result
1216 1181
@@ -1218,10 +1183,6 b' class CaselessStrEnum(Enum):'
1218 1183 """An enum of strings that are caseless in validate."""
1219 1184
1220 1185 def validate(self, obj, value):
1221 if value is None:
1222 if self._allow_none:
1223 return value
1224
1225 1186 if not isinstance(value, py3compat.string_types):
1226 1187 self.error(obj, value)
1227 1188
@@ -1384,7 +1345,7 b' class List(Container):'
1384 1345 self.length_error(obj, value)
1385 1346
1386 1347 return super(List, self).validate_elements(obj, value)
1387
1348
1388 1349 def validate(self, obj, value):
1389 1350 value = super(List, self).validate(obj, value)
1390 1351 if value is None:
@@ -1393,7 +1354,7 b' class List(Container):'
1393 1354 value = self.validate_elements(obj, value)
1394 1355
1395 1356 return value
1396
1357
1397 1358
1398 1359
1399 1360 class Set(List):
@@ -1513,7 +1474,7 b' class Dict(Instance):'
1513 1474 super(Dict,self).__init__(klass=dict, args=args,
1514 1475 allow_none=allow_none, **metadata)
1515 1476
1516 class TCPAddress(AllowNone):
1477 class TCPAddress(TraitType):
1517 1478 """A trait for an (ip, port) tuple.
1518 1479
1519 1480 This allows for both IPv4 IP addresses as well as hostnames.
@@ -1529,11 +1490,9 b' class TCPAddress(AllowNone):'
1529 1490 port = value[1]
1530 1491 if port >= 0 and port <= 65535:
1531 1492 return value
1532 if self._none_ok(value):
1533 return value
1534 1493 self.error(obj, value)
1535 1494
1536 class CRegExp(AllowNone):
1495 class CRegExp(TraitType):
1537 1496 """A casting compiled regular expression trait.
1538 1497
1539 1498 Accepts both strings and compiled regular expressions. The resulting
@@ -1545,6 +1504,4 b' class CRegExp(AllowNone):'
1545 1504 try:
1546 1505 return re.compile(value)
1547 1506 except:
1548 if self._none_ok(value):
1549 return value
1550 1507 self.error(obj, value)
General Comments 0
You need to be logged in to leave comments. Login now