##// END OF EJS Templates
Fixing subtle bug in the traitlets with This....
Fixing subtle bug in the traitlets with This. Previously subclasses This traitlets wouldn't accept superclass instances as values. I have added a this_class attribute to TraitletType that is set by the metaclass and is used later by This.validate to properly handle this case. I have also added new tests for this.

File last commit:

r2183:0c46f18e
r2183:0c46f18e
Show More
test_traitlets.py
645 lines | 16.9 KiB | text/x-python | PythonLexer
Brian Granger
More work on traitlets.py. I have added tests for existing traitlets.
r2175 #!/usr/bin/env python
# encoding: utf-8
"""
Tests for IPython.utils.traitlets.
Authors:
* Brian Granger
* Enthought, Inc. Some of the code in this file comes from enthought.traits
and is licensed under the BSD license. Also, many of the ideas also come
from enthought.traits even though our implementation is very different.
"""
#-----------------------------------------------------------------------------
# Copyright (C) 2008-2009 The IPython Development Team
#
# Distributed under the terms of the BSD License. The full license is in
# the file COPYING, distributed as part of this software.
#-----------------------------------------------------------------------------
#-----------------------------------------------------------------------------
# Imports
#-----------------------------------------------------------------------------
import sys
import os
from unittest import TestCase
from IPython.utils.traitlets import (
HasTraitlets, MetaHasTraitlets, TraitletType, Any,
Brian Granger
Added support for Type and Instance traitlets with testing.
r2177 Int, Long, Float, Complex, Str, Unicode, Bool, TraitletError,
Brian Granger
Important changes to simplify traitlets....
r2182 Undefined, Type, This, Instance
Brian Granger
More work on traitlets.py. I have added tests for existing traitlets.
r2175 )
#-----------------------------------------------------------------------------
# Helper classes for testing
#-----------------------------------------------------------------------------
Brian Granger
Important changes to simplify traitlets....
r2182 class HasTraitletsStub(HasTraitlets):
Brian Granger
More work on traitlets.py. I have added tests for existing traitlets.
r2175
Brian Granger
A few more small traitlets features.
r2179 def _notify_traitlet(self, name, old, new):
Brian Granger
More work on traitlets.py. I have added tests for existing traitlets.
r2175 self._notify_name = name
self._notify_old = old
self._notify_new = new
#-----------------------------------------------------------------------------
# Test classes
#-----------------------------------------------------------------------------
class TestTraitletType(TestCase):
Brian Granger
Added support for Type and Instance traitlets with testing.
r2177 def test_get_undefined(self):
Brian Granger
Important changes to simplify traitlets....
r2182 class A(HasTraitlets):
a = TraitletType
a = A()
self.assertEquals(a.a, Undefined)
Brian Granger
More work on traitlets.py. I have added tests for existing traitlets.
r2175
def test_set(self):
Brian Granger
Important changes to simplify traitlets....
r2182 class A(HasTraitletsStub):
a = TraitletType
a = A()
a.a = 10
self.assertEquals(a.a, 10)
self.assertEquals(a._notify_name, 'a')
self.assertEquals(a._notify_old, Undefined)
self.assertEquals(a._notify_new, 10)
Brian Granger
More work on traitlets.py. I have added tests for existing traitlets.
r2175
def test_validate(self):
class MyTT(TraitletType):
def validate(self, inst, value):
return -1
Brian Granger
Important changes to simplify traitlets....
r2182 class A(HasTraitletsStub):
tt = MyTT
a = A()
a.tt = 10
self.assertEquals(a.tt, -1)
Brian Granger
More work on traitlets.py. I have added tests for existing traitlets.
r2175
Brian Granger
Added support for Type and Instance traitlets with testing.
r2177 def test_default_validate(self):
class MyIntTT(TraitletType):
def validate(self, obj, value):
if isinstance(value, int):
return value
self.error(obj, value)
Brian Granger
Important changes to simplify traitlets....
r2182 class A(HasTraitlets):
tt = MyIntTT(10)
a = A()
self.assertEquals(a.tt, 10)
# Defaults are validated when the HasTraitlets is instantiated
class B(HasTraitlets):
tt = MyIntTT('bad default')
self.assertRaises(TraitletError, B)
Brian Granger
Added support for Type and Instance traitlets with testing.
r2177
Brian Granger
More work on traitlets.py. I have added tests for existing traitlets.
r2175 def test_is_valid_for(self):
class MyTT(TraitletType):
def is_valid_for(self, value):
return True
Brian Granger
Important changes to simplify traitlets....
r2182 class A(HasTraitlets):
tt = MyTT
a = A()
a.tt = 10
self.assertEquals(a.tt, 10)
Brian Granger
More work on traitlets.py. I have added tests for existing traitlets.
r2175
def test_value_for(self):
class MyTT(TraitletType):
def value_for(self, value):
return 20
Brian Granger
Important changes to simplify traitlets....
r2182 class A(HasTraitlets):
tt = MyTT
a = A()
a.tt = 10
self.assertEquals(a.tt, 20)
Brian Granger
More work on traitlets.py. I have added tests for existing traitlets.
r2175
def test_info(self):
Brian Granger
Important changes to simplify traitlets....
r2182 class A(HasTraitlets):
tt = TraitletType
a = A()
self.assertEquals(A.tt.info(), 'any value')
Brian Granger
More work on traitlets.py. I have added tests for existing traitlets.
r2175
def test_error(self):
Brian Granger
Important changes to simplify traitlets....
r2182 class A(HasTraitlets):
tt = TraitletType
a = A()
self.assertRaises(TraitletError, A.tt.error, a, 10)
Brian Granger
More work on traitlets.py. I have added tests for existing traitlets.
r2175
class TestHasTraitletsMeta(TestCase):
def test_metaclass(self):
self.assertEquals(type(HasTraitlets), MetaHasTraitlets)
class A(HasTraitlets):
a = Int
a = A()
self.assertEquals(type(a.__class__), MetaHasTraitlets)
self.assertEquals(a.a,0)
a.a = 10
self.assertEquals(a.a,10)
class B(HasTraitlets):
b = Int()
b = B()
self.assertEquals(b.b,0)
b.b = 10
self.assertEquals(b.b,10)
class C(HasTraitlets):
c = Int(30)
c = C()
self.assertEquals(c.c,30)
c.c = 10
self.assertEquals(c.c,10)
Brian Granger
Fixing subtle bug in the traitlets with This....
r2183 def test_this_class(self):
class A(HasTraitlets):
t = This()
tt = This()
class B(A):
tt = This()
ttt = This()
self.assertEquals(A.t.this_class, A)
self.assertEquals(B.t.this_class, A)
self.assertEquals(B.tt.this_class, B)
self.assertEquals(B.ttt.this_class, B)
Brian Granger
More work on traitlets.py. I have added tests for existing traitlets.
r2175
class TestHasTraitletsNotify(TestCase):
def setUp(self):
self._notify1 = []
self._notify2 = []
def notify1(self, name, old, new):
self._notify1.append((name, old, new))
def notify2(self, name, old, new):
self._notify2.append((name, old, new))
def test_notify_all(self):
class A(HasTraitlets):
a = Int
b = Float
a = A()
a.on_traitlet_change(self.notify1)
a.a = 0
self.assertEquals(len(self._notify1),0)
a.b = 0.0
self.assertEquals(len(self._notify1),0)
a.a = 10
self.assert_(('a',0,10) in self._notify1)
a.b = 10.0
self.assert_(('b',0.0,10.0) in self._notify1)
self.assertRaises(TraitletError,setattr,a,'a','bad string')
self.assertRaises(TraitletError,setattr,a,'b','bad string')
self._notify1 = []
a.on_traitlet_change(self.notify1,remove=True)
a.a = 20
a.b = 20.0
self.assertEquals(len(self._notify1),0)
def test_notify_one(self):
class A(HasTraitlets):
a = Int
b = Float
a = A()
a.on_traitlet_change(self.notify1, 'a')
a.a = 0
self.assertEquals(len(self._notify1),0)
a.a = 10
self.assert_(('a',0,10) in self._notify1)
self.assertRaises(TraitletError,setattr,a,'a','bad string')
def test_subclass(self):
class A(HasTraitlets):
a = Int
class B(A):
b = Float
b = B()
self.assertEquals(b.a,0)
self.assertEquals(b.b,0.0)
b.a = 100
b.b = 100.0
self.assertEquals(b.a,100)
self.assertEquals(b.b,100.0)
def test_notify_subclass(self):
class A(HasTraitlets):
a = Int
class B(A):
b = Float
b = B()
b.on_traitlet_change(self.notify1, 'a')
b.on_traitlet_change(self.notify2, 'b')
b.a = 0
b.b = 0.0
self.assertEquals(len(self._notify1),0)
self.assertEquals(len(self._notify2),0)
b.a = 10
b.b = 10.0
self.assert_(('a',0,10) in self._notify1)
self.assert_(('b',0.0,10.0) in self._notify2)
def test_static_notify(self):
class A(HasTraitlets):
a = Int
_notify1 = []
def _a_changed(self, name, old, new):
self._notify1.append((name, old, new))
a = A()
a.a = 0
Brian Granger
Important changes to simplify traitlets....
r2182 # This is broken!!!
Brian Granger
More work on traitlets.py. I have added tests for existing traitlets.
r2175 self.assertEquals(len(a._notify1),0)
a.a = 10
self.assert_(('a',0,10) in a._notify1)
class B(A):
b = Float
_notify2 = []
def _b_changed(self, name, old, new):
self._notify2.append((name, old, new))
b = B()
b.a = 10
b.b = 10.0
self.assert_(('a',0,10) in b._notify1)
self.assert_(('b',0.0,10.0) in b._notify2)
def test_notify_args(self):
def callback0():
self.cb = ()
def callback1(name):
self.cb = (name,)
def callback2(name, new):
self.cb = (name, new)
def callback3(name, old, new):
self.cb = (name, old, new)
class A(HasTraitlets):
a = Int
a = A()
a.on_traitlet_change(callback0, 'a')
a.a = 10
self.assertEquals(self.cb,())
a.on_traitlet_change(callback0, 'a', remove=True)
a.on_traitlet_change(callback1, 'a')
a.a = 100
self.assertEquals(self.cb,('a',))
a.on_traitlet_change(callback1, 'a', remove=True)
a.on_traitlet_change(callback2, 'a')
a.a = 1000
self.assertEquals(self.cb,('a',1000))
a.on_traitlet_change(callback2, 'a', remove=True)
a.on_traitlet_change(callback3, 'a')
a.a = 10000
self.assertEquals(self.cb,('a',1000,10000))
a.on_traitlet_change(callback3, 'a', remove=True)
self.assertEquals(len(a._traitlet_notifiers['a']),0)
Brian Granger
A few more small traitlets features.
r2179 class TestTraitletKeys(TestCase):
def test_keys(self):
class A(HasTraitlets):
a = Int
b = Float
a = A()
Brian Granger
Fixing subtle bug in the traitlets with This....
r2183 self.assertEquals(a.traitlet_names(),['a','b'])
Brian Granger
A few more small traitlets features.
r2179
Brian Granger
More work on traitlets.py. I have added tests for existing traitlets.
r2175
#-----------------------------------------------------------------------------
# Tests for specific traitlet types
#-----------------------------------------------------------------------------
Brian Granger
Added support for Type and Instance traitlets with testing.
r2177
class TestType(TestCase):
def test_default(self):
class B(object): pass
class A(HasTraitlets):
klass = Type
a = A()
self.assertEquals(a.klass, None)
a.klass = B
self.assertEquals(a.klass, B)
self.assertRaises(TraitletError, setattr, a, 'klass', 10)
def test_value(self):
class B(object): pass
class C(object): pass
class A(HasTraitlets):
klass = Type(B)
a = A()
self.assertEquals(a.klass, B)
self.assertRaises(TraitletError, setattr, a, 'klass', C)
self.assertRaises(TraitletError, setattr, a, 'klass', object)
a.klass = B
def test_allow_none(self):
class B(object): pass
class C(B): pass
class A(HasTraitlets):
klass = Type(B, allow_none=False)
a = A()
self.assertEquals(a.klass, B)
self.assertRaises(TraitletError, setattr, a, 'klass', None)
a.klass = C
self.assertEquals(a.klass, C)
Brian Granger
Important changes to simplify traitlets....
r2182 def test_validate_klass(self):
def inner():
class A(HasTraitlets):
klass = Type('no strings allowed')
self.assertRaises(TraitletError, inner)
def test_validate_default(self):
class B(object): pass
class A(HasTraitlets):
klass = Type('bad default', B)
self.assertRaises(TraitletError, A)
class C(HasTraitlets):
klass = Type(None, B, allow_none=False)
self.assertRaises(TraitletError, C)
Brian Granger
Added support for Type and Instance traitlets with testing.
r2177
class TestInstance(TestCase):
def test_basic(self):
class Foo(object): pass
class Bar(Foo): pass
class Bah(object): pass
class A(HasTraitlets):
inst = Instance(Foo)
a = A()
Brian Granger
Important changes to simplify traitlets....
r2182 self.assert_(a.inst is None)
Brian Granger
Added support for Type and Instance traitlets with testing.
r2177 a.inst = Foo()
self.assert_(isinstance(a.inst, Foo))
a.inst = Bar()
self.assert_(isinstance(a.inst, Foo))
self.assertRaises(TraitletError, setattr, a, 'inst', Foo)
self.assertRaises(TraitletError, setattr, a, 'inst', Bar)
self.assertRaises(TraitletError, setattr, a, 'inst', Bah())
def test_unique_default_value(self):
class Foo(object): pass
class A(HasTraitlets):
Brian Granger
Important changes to simplify traitlets....
r2182 inst = Instance(Foo,(),{})
Brian Granger
Added support for Type and Instance traitlets with testing.
r2177
a = A()
b = A()
self.assert_(a.inst is not b.inst)
def test_args_kw(self):
class Foo(object):
def __init__(self, c): self.c = c
Brian Granger
Important changes to simplify traitlets....
r2182 class Bar(object): pass
class Bah(object):
def __init__(self, c, d):
self.c = c; self.d = d
Brian Granger
Added support for Type and Instance traitlets with testing.
r2177
class A(HasTraitlets):
Brian Granger
Important changes to simplify traitlets....
r2182 inst = Instance(Foo, (10,))
Brian Granger
Added support for Type and Instance traitlets with testing.
r2177 a = A()
self.assertEquals(a.inst.c, 10)
class B(HasTraitlets):
Brian Granger
Important changes to simplify traitlets....
r2182 inst = Instance(Bah, args=(10,), kw=dict(d=20))
Brian Granger
Added support for Type and Instance traitlets with testing.
r2177 b = B()
self.assertEquals(b.inst.c, 10)
self.assertEquals(b.inst.d, 20)
Brian Granger
Important changes to simplify traitlets....
r2182 class C(HasTraitlets):
inst = Instance(Foo)
c = C()
self.assert_(c.inst is None)
def test_bad_default(self):
Brian Granger
Added support for Type and Instance traitlets with testing.
r2177 class Foo(object): pass
class A(HasTraitlets):
Brian Granger
Important changes to simplify traitlets....
r2182 inst = Instance(Foo, allow_none=False)
Brian Granger
Added support for Type and Instance traitlets with testing.
r2177
Brian Granger
Important changes to simplify traitlets....
r2182 self.assertRaises(TraitletError, A)
def test_instance(self):
class Foo(object): pass
def inner():
class A(HasTraitlets):
inst = Instance(Foo())
self.assertRaises(TraitletError, inner)
Brian Granger
Added support for Type and Instance traitlets with testing.
r2177
Brian Granger
Improvements to component.py....
r2180
class TestThis(TestCase):
def test_this_class(self):
class Foo(HasTraitlets):
this = This
f = Foo()
self.assertEquals(f.this, None)
g = Foo()
f.this = g
self.assertEquals(f.this, g)
self.assertRaises(TraitletError, setattr, f, 'this', 10)
def test_this_inst(self):
class Foo(HasTraitlets):
this = This()
f = Foo()
f.this = Foo()
self.assert_(isinstance(f.this, Foo))
Brian Granger
Fixing subtle bug in the traitlets with This....
r2183 def test_subclass(self):
class Foo(HasTraitlets):
t = This()
class Bar(Foo):
pass
f = Foo()
b = Bar()
f.t = b
b.t = f
self.assertEquals(f.t, b)
self.assertEquals(b.t, f)
def test_subclass_override(self):
class Foo(HasTraitlets):
t = This()
class Bar(Foo):
t = This()
f = Foo()
b = Bar()
f.t = b
self.assertEquals(f.t, b)
self.assertRaises(TraitletError, setattr, b, 't', f)
Brian Granger
Improvements to component.py....
r2180
Brian Granger
More work on traitlets.py. I have added tests for existing traitlets.
r2175 class TraitletTestBase(TestCase):
Brian Granger
Added support for Type and Instance traitlets with testing.
r2177 """A best testing class for basic traitlet types."""
Brian Granger
More work on traitlets.py. I have added tests for existing traitlets.
r2175
def assign(self, value):
self.obj.value = value
def coerce(self, value):
return value
def test_good_values(self):
if hasattr(self, '_good_values'):
for value in self._good_values:
self.assign(value)
self.assertEquals(self.obj.value, self.coerce(value))
def test_bad_values(self):
if hasattr(self, '_bad_values'):
for value in self._bad_values:
self.assertRaises(TraitletError, self.assign, value)
def test_default_value(self):
if hasattr(self, '_default_value'):
self.assertEquals(self._default_value, self.obj.value)
class AnyTraitlet(HasTraitlets):
value = Any
class AnyTraitTest(TraitletTestBase):
obj = AnyTraitlet()
_default_value = None
_good_values = [10.0, 'ten', u'ten', [10], {'ten': 10},(10,), None, 1j]
_bad_values = []
class IntTraitlet(HasTraitlets):
value = Int(99)
class TestInt(TraitletTestBase):
obj = IntTraitlet()
_default_value = 99
_good_values = [10, -10]
_bad_values = ['ten', u'ten', [10], {'ten': 10},(10,), None, 1j, 10L,
-10L, 10.1, -10.1, '10L', '-10L', '10.1', '-10.1', u'10L',
u'-10L', u'10.1', u'-10.1', '10', '-10', u'10', u'-10']
class LongTraitlet(HasTraitlets):
value = Long(99L)
class TestLong(TraitletTestBase):
obj = LongTraitlet()
_default_value = 99L
_good_values = [10, -10, 10L, -10L]
_bad_values = ['ten', u'ten', [10], [10l], {'ten': 10},(10,),(10L,),
None, 1j, 10.1, -10.1, '10', '-10', '10L', '-10L', '10.1',
'-10.1', u'10', u'-10', u'10L', u'-10L', u'10.1',
u'-10.1']
class FloatTraitlet(HasTraitlets):
value = Float(99.0)
class TestFloat(TraitletTestBase):
obj = FloatTraitlet()
_default_value = 99.0
_good_values = [10, -10, 10.1, -10.1]
_bad_values = [10L, -10L, 'ten', u'ten', [10], {'ten': 10},(10,), None,
1j, '10', '-10', '10L', '-10L', '10.1', '-10.1', u'10',
u'-10', u'10L', u'-10L', u'10.1', u'-10.1']
class ComplexTraitlet(HasTraitlets):
value = Complex(99.0-99.0j)
class TestComplex(TraitletTestBase):
obj = ComplexTraitlet()
_default_value = 99.0-99.0j
_good_values = [10, -10, 10.1, -10.1, 10j, 10+10j, 10-10j,
10.1j, 10.1+10.1j, 10.1-10.1j]
_bad_values = [10L, -10L, u'10L', u'-10L', 'ten', [10], {'ten': 10},(10,), None]
class StringTraitlet(HasTraitlets):
value = Str('string')
class TestString(TraitletTestBase):
obj = StringTraitlet()
_default_value = 'string'
_good_values = ['10', '-10', '10L',
'-10L', '10.1', '-10.1', 'string']
_bad_values = [10, -10, 10L, -10L, 10.1, -10.1, 1j, [10],
['ten'],{'ten': 10},(10,), None, u'string']
class UnicodeTraitlet(HasTraitlets):
value = Unicode(u'unicode')
class TestUnicode(TraitletTestBase):
obj = UnicodeTraitlet()
_default_value = u'unicode'
_good_values = ['10', '-10', '10L', '-10L', '10.1',
'-10.1', '', u'', 'string', u'string', ]
_bad_values = [10, -10, 10L, -10L, 10.1, -10.1, 1j,
[10], ['ten'], [u'ten'], {'ten': 10},(10,), None]