Show More
@@ -20,7 +20,7 b' from IPython.utils.traitlets import (' | |||||
20 | Int, Long, Integer, Float, Complex, Bytes, Unicode, TraitError, |
|
20 | Int, Long, Integer, Float, Complex, Bytes, Unicode, TraitError, | |
21 | Undefined, Type, This, Instance, TCPAddress, List, Tuple, |
|
21 | Undefined, Type, This, Instance, TCPAddress, List, Tuple, | |
22 | ObjectName, DottedObjectName, CRegExp, link, directional_link, |
|
22 | ObjectName, DottedObjectName, CRegExp, link, directional_link, | |
23 | EventfulList, EventfulDict |
|
23 | EventfulList, EventfulDict, ForwardDeclaredType, ForwardDeclaredInstance, | |
24 | ) |
|
24 | ) | |
25 | from IPython.utils import py3compat |
|
25 | from IPython.utils import py3compat | |
26 | from IPython.testing.decorators import skipif |
|
26 | from IPython.testing.decorators import skipif | |
@@ -684,6 +684,20 b' class TestThis(TestCase):' | |||||
684 | self.assertEqual(f.t, b) |
|
684 | self.assertEqual(f.t, b) | |
685 | self.assertRaises(TraitError, setattr, b, 't', f) |
|
685 | self.assertRaises(TraitError, setattr, b, 't', f) | |
686 |
|
686 | |||
|
687 | def test_this_in_container(self): | |||
|
688 | ||||
|
689 | class Tree(HasTraits): | |||
|
690 | value = Unicode() | |||
|
691 | leaves = List(This()) | |||
|
692 | ||||
|
693 | tree = Tree( | |||
|
694 | value='foo', | |||
|
695 | leaves=[Tree('bar'), Tree('buzz')] | |||
|
696 | ) | |||
|
697 | ||||
|
698 | with self.assertRaises(TraitError): | |||
|
699 | tree.leaves = [1, 2] | |||
|
700 | ||||
687 | class TraitTestBase(TestCase): |
|
701 | class TraitTestBase(TestCase): | |
688 | """A best testing class for basic trait types.""" |
|
702 | """A best testing class for basic trait types.""" | |
689 |
|
703 | |||
@@ -1306,3 +1320,103 b' class TestEventful(TestCase):' | |||||
1306 |
|
1320 | |||
1307 | # Is the output correct? |
|
1321 | # Is the output correct? | |
1308 | self.assertEqual(a.x, {c: c for c in 'bz'}) |
|
1322 | self.assertEqual(a.x, {c: c for c in 'bz'}) | |
|
1323 | ||||
|
1324 | ### | |||
|
1325 | # Traits for Forward Declaration Tests | |||
|
1326 | ### | |||
|
1327 | class ForwardDeclaredInstanceTrait(HasTraits): | |||
|
1328 | ||||
|
1329 | value = ForwardDeclaredInstance('ForwardDeclaredBar') | |||
|
1330 | ||||
|
1331 | class ForwardDeclaredTypeTrait(HasTraits): | |||
|
1332 | ||||
|
1333 | value = ForwardDeclaredType('ForwardDeclaredBar') | |||
|
1334 | ||||
|
1335 | class ForwardDeclaredInstanceListTrait(HasTraits): | |||
|
1336 | ||||
|
1337 | value = List(ForwardDeclaredInstance('ForwardDeclaredBar')) | |||
|
1338 | ||||
|
1339 | class ForwardDeclaredTypeListTrait(HasTraits): | |||
|
1340 | ||||
|
1341 | value = List(ForwardDeclaredType('ForwardDeclaredBar')) | |||
|
1342 | ### | |||
|
1343 | # End Traits for Forward Declaration Tests | |||
|
1344 | ### | |||
|
1345 | ||||
|
1346 | ### | |||
|
1347 | # Classes for Forward Declaration Tests | |||
|
1348 | ### | |||
|
1349 | class ForwardDeclaredBar(object): | |||
|
1350 | pass | |||
|
1351 | ||||
|
1352 | class ForwardDeclaredBarSub(ForwardDeclaredBar): | |||
|
1353 | pass | |||
|
1354 | ### | |||
|
1355 | # End Classes for Forward Declaration Tests | |||
|
1356 | ### | |||
|
1357 | ||||
|
1358 | ### | |||
|
1359 | # Forward Declaration Tests | |||
|
1360 | ### | |||
|
1361 | class TestForwardDeclaredInstanceTrait(TraitTestBase): | |||
|
1362 | ||||
|
1363 | obj = ForwardDeclaredInstanceTrait() | |||
|
1364 | _default_value = None | |||
|
1365 | _good_values = [None, ForwardDeclaredBar(), ForwardDeclaredBarSub()] | |||
|
1366 | _bad_values = ['foo', 3, ForwardDeclaredBar, ForwardDeclaredBarSub] | |||
|
1367 | ||||
|
1368 | class TestForwardDeclaredTypeTrait(TraitTestBase): | |||
|
1369 | ||||
|
1370 | obj = ForwardDeclaredTypeTrait() | |||
|
1371 | _default_value = None | |||
|
1372 | _good_values = [None, ForwardDeclaredBar, ForwardDeclaredBarSub] | |||
|
1373 | _bad_values = ['foo', 3, ForwardDeclaredBar(), ForwardDeclaredBarSub()] | |||
|
1374 | ||||
|
1375 | class TestForwardDeclaredInstanceList(TraitTestBase): | |||
|
1376 | ||||
|
1377 | obj = ForwardDeclaredInstanceListTrait() | |||
|
1378 | ||||
|
1379 | def test_klass(self): | |||
|
1380 | """Test that the instance klass is properly assigned.""" | |||
|
1381 | self.assertIs(self.obj.traits()['value']._trait.klass, ForwardDeclaredBar) | |||
|
1382 | ||||
|
1383 | _default_value = [] | |||
|
1384 | _good_values = [ | |||
|
1385 | [ForwardDeclaredBar(), ForwardDeclaredBarSub(), None], | |||
|
1386 | [None], | |||
|
1387 | [], | |||
|
1388 | None, | |||
|
1389 | ] | |||
|
1390 | _bad_values = [ | |||
|
1391 | ForwardDeclaredBar(), | |||
|
1392 | [ForwardDeclaredBar(), 3], | |||
|
1393 | '1', | |||
|
1394 | # Note that this is the type, not an instance. | |||
|
1395 | [ForwardDeclaredBar] | |||
|
1396 | ] | |||
|
1397 | ||||
|
1398 | class TestForwardDeclaredTypeList(TraitTestBase): | |||
|
1399 | ||||
|
1400 | obj = ForwardDeclaredTypeListTrait() | |||
|
1401 | ||||
|
1402 | def test_klass(self): | |||
|
1403 | """Test that the instance klass is properly assigned.""" | |||
|
1404 | self.assertIs(self.obj.traits()['value']._trait.klass, ForwardDeclaredBar) | |||
|
1405 | ||||
|
1406 | _default_value = [] | |||
|
1407 | _good_values = [ | |||
|
1408 | [ForwardDeclaredBar, ForwardDeclaredBarSub, None], | |||
|
1409 | [], | |||
|
1410 | [None], | |||
|
1411 | None, | |||
|
1412 | ] | |||
|
1413 | _bad_values = [ | |||
|
1414 | ForwardDeclaredBar, | |||
|
1415 | [ForwardDeclaredBar, 3], | |||
|
1416 | '1', | |||
|
1417 | # Note that this is an instance, not the type. | |||
|
1418 | [ForwardDeclaredBar()] | |||
|
1419 | ] | |||
|
1420 | ### | |||
|
1421 | # End Forward Declaration Tests | |||
|
1422 | ### |
@@ -748,7 +748,16 b' class HasTraits(py3compat.with_metaclass(MetaHasTraits, object)):' | |||||
748 |
|
748 | |||
749 |
|
749 | |||
750 | class ClassBasedTraitType(TraitType): |
|
750 | class ClassBasedTraitType(TraitType): | |
751 | """A trait with error reporting for Type, Instance and This.""" |
|
751 | """ | |
|
752 | A trait with error reporting and string -> type resolution for Type, | |||
|
753 | Instance and This. | |||
|
754 | """ | |||
|
755 | ||||
|
756 | def _resolve_string(self, string): | |||
|
757 | """ | |||
|
758 | Resolve a string supplied for a type into an actual object. | |||
|
759 | """ | |||
|
760 | return import_item(string) | |||
752 |
|
761 | |||
753 | def error(self, obj, value): |
|
762 | def error(self, obj, value): | |
754 | kind = type(value) |
|
763 | kind = type(value) | |
@@ -813,7 +822,7 b' class Type(ClassBasedTraitType):' | |||||
813 | """Validates that the value is a valid object instance.""" |
|
822 | """Validates that the value is a valid object instance.""" | |
814 | if isinstance(value, py3compat.string_types): |
|
823 | if isinstance(value, py3compat.string_types): | |
815 | try: |
|
824 | try: | |
816 |
value = |
|
825 | value = self._resolve_string(value) | |
817 | except ImportError: |
|
826 | except ImportError: | |
818 | raise TraitError("The '%s' trait of %s instance must be a type, but " |
|
827 | raise TraitError("The '%s' trait of %s instance must be a type, but " | |
819 | "%r could not be imported" % (self.name, obj, value)) |
|
828 | "%r could not be imported" % (self.name, obj, value)) | |
@@ -842,9 +851,9 b' class Type(ClassBasedTraitType):' | |||||
842 |
|
851 | |||
843 | def _resolve_classes(self): |
|
852 | def _resolve_classes(self): | |
844 | if isinstance(self.klass, py3compat.string_types): |
|
853 | if isinstance(self.klass, py3compat.string_types): | |
845 |
self.klass = |
|
854 | self.klass = self._resolve_string(self.klass) | |
846 | if isinstance(self.default_value, py3compat.string_types): |
|
855 | if isinstance(self.default_value, py3compat.string_types): | |
847 |
self.default_value = |
|
856 | self.default_value = self._resolve_string(self.default_value) | |
848 |
|
857 | |||
849 | def get_default_value(self): |
|
858 | def get_default_value(self): | |
850 | return self.default_value |
|
859 | return self.default_value | |
@@ -951,7 +960,7 b' class Instance(ClassBasedTraitType):' | |||||
951 |
|
960 | |||
952 | def _resolve_classes(self): |
|
961 | def _resolve_classes(self): | |
953 | if isinstance(self.klass, py3compat.string_types): |
|
962 | if isinstance(self.klass, py3compat.string_types): | |
954 |
self.klass = |
|
963 | self.klass = self._resolve_string(self.klass) | |
955 |
|
964 | |||
956 | def get_default_value(self): |
|
965 | def get_default_value(self): | |
957 | """Instantiate a default value instance. |
|
966 | """Instantiate a default value instance. | |
@@ -967,6 +976,33 b' class Instance(ClassBasedTraitType):' | |||||
967 | return dv |
|
976 | return dv | |
968 |
|
977 | |||
969 |
|
978 | |||
|
979 | class ForwardDeclaredMixin(object): | |||
|
980 | """ | |||
|
981 | Mixin for forward-declared versions of Instance and Type. | |||
|
982 | """ | |||
|
983 | def _resolve_string(self, string): | |||
|
984 | """ | |||
|
985 | Find the specified class name by looking for it in the module in which | |||
|
986 | our this_class attribute was defined. | |||
|
987 | """ | |||
|
988 | modname = self.this_class.__module__ | |||
|
989 | return import_item('.'.join([modname, string])) | |||
|
990 | ||||
|
991 | ||||
|
992 | class ForwardDeclaredType(ForwardDeclaredMixin, Type): | |||
|
993 | """ | |||
|
994 | Forward-declared version of Type. | |||
|
995 | """ | |||
|
996 | pass | |||
|
997 | ||||
|
998 | ||||
|
999 | class ForwardDeclaredInstance(ForwardDeclaredMixin, Instance): | |||
|
1000 | """ | |||
|
1001 | Forward-declared version of Instance. | |||
|
1002 | """ | |||
|
1003 | pass | |||
|
1004 | ||||
|
1005 | ||||
970 | class This(ClassBasedTraitType): |
|
1006 | class This(ClassBasedTraitType): | |
971 | """A trait for instances of the class containing this trait. |
|
1007 | """A trait for instances of the class containing this trait. | |
972 |
|
1008 | |||
@@ -1354,8 +1390,10 b' class Container(Instance):' | |||||
1354 | return self.klass(validated) |
|
1390 | return self.klass(validated) | |
1355 |
|
1391 | |||
1356 | def instance_init(self, obj): |
|
1392 | def instance_init(self, obj): | |
1357 |
if isinstance(self._trait, |
|
1393 | if isinstance(self._trait, TraitType): | |
1358 |
self._trait. |
|
1394 | self._trait.this_class = self.this_class | |
|
1395 | if hasattr(self._trait, 'instance_init'): | |||
|
1396 | self._trait.instance_init(obj) | |||
1359 | super(Container, self).instance_init(obj) |
|
1397 | super(Container, self).instance_init(obj) | |
1360 |
|
1398 | |||
1361 |
|
1399 |
General Comments 0
You need to be logged in to leave comments.
Login now