-
-
Notifications
You must be signed in to change notification settings - Fork 73
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Defined namespace and implementation on Parameters object (#230)
Moves most of the code of `Parameterized` onto a `param` object of type `Parameters`, which also acts as a namespace. The goal is to make this the face of the public API, cleaning up the namespace of user classes. The new API is likely to change as we clean it up, but the previous API remains available, so existing code should not be affected. The previous API will be deprecated at some point in the future; `Parameters._disable_stubs` can be used to control deprecation warnings/errors/silence. Docstrings of methods on Parameterized that have moved to Parameters point readers to the new methods. Existing tests have been copied into an `API0` subdirectory, while tests in `API1` use the Parameters namespace. (This wholesale copying could probably be improved in the future.) Ideally, `dir()` would already return only the cleaned up namespace (i.e. not the deprecated methods on `Parameterized`), but this has not been done yet and may not be easy.
- Loading branch information
Showing
40 changed files
with
2,945 additions
and
858 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Large diffs are not rendered by default.
Oops, something went wrong.
Empty file.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
import param | ||
import unittest | ||
|
||
class API1TestCase(unittest.TestCase): | ||
|
||
def setUp(self): | ||
param.parameterized.Parameters._disable_stubs = True | ||
|
||
def tearDown(self): | ||
param.parameterized.Parameters._disable_stubs = False |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
""" | ||
Unit test for ClassSelector parameters. | ||
""" | ||
|
||
|
||
from numbers import Number | ||
|
||
import param | ||
from . import API1TestCase | ||
|
||
|
||
class TestClassSelectorParameters(API1TestCase): | ||
|
||
def setUp(self): | ||
super(TestClassSelectorParameters, self).setUp() | ||
class P(param.Parameterized): | ||
e = param.ClassSelector(default=1,class_=int) | ||
f = param.ClassSelector(default=int,class_=Number, is_instance=False) | ||
g = param.ClassSelector(default=1,class_=(int,str)) | ||
h = param.ClassSelector(default=int,class_=(int,str), is_instance=False) | ||
|
||
self.P = P | ||
|
||
def test_single_class_instance_constructor(self): | ||
p = self.P(e=6) | ||
self.assertEqual(p.e, 6) | ||
|
||
def test_single_class_instance_error(self): | ||
exception = "Parameter 'e' value must be an instance of int, not 'a'" | ||
with self.assertRaisesRegexp(ValueError, exception): | ||
p = self.P(e='a') | ||
|
||
def test_single_class_type_constructor(self): | ||
p = self.P(f=float) | ||
self.assertEqual(p.f, float) | ||
|
||
def test_single_class_type_error(self): | ||
exception = "Parameter 'str' must be a subclass of Number, not 'type'" | ||
with self.assertRaisesRegexp(ValueError, exception): | ||
p = self.P(f=str) | ||
|
||
def test_multiple_class_instance_constructor1(self): | ||
p = self.P(g=1) | ||
self.assertEqual(p.g, 1) | ||
|
||
def test_multiple_class_instance_constructor2(self): | ||
p = self.P(g='A') | ||
self.assertEqual(p.g, 'A') | ||
|
||
def test_multiple_class_instance_error(self): | ||
exception = "Parameter 'g' value must be an instance of \(int, str\), not '3.0'" | ||
with self.assertRaisesRegexp(ValueError, exception): | ||
p = self.P(g=3.0) | ||
|
||
def test_multiple_class_type_constructor1(self): | ||
p = self.P(h=int) | ||
self.assertEqual(p.h, int) | ||
|
||
def test_multiple_class_type_constructor2(self): | ||
p = self.P(h=str) | ||
self.assertEqual(p.h, str) | ||
|
||
def test_multiple_class_type_error(self): | ||
exception = "Parameter 'float' must be a subclass of \(int, str\), not 'type'" | ||
with self.assertRaisesRegexp(ValueError, exception): | ||
p = self.P(h=float) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
""" | ||
Unit test for Color parameters. | ||
""" | ||
import param | ||
from . import API1TestCase | ||
|
||
class TestColorParameters(API1TestCase): | ||
|
||
def test_initialization_invalid_string(self): | ||
try: | ||
class Q(param.Parameterized): | ||
q = param.Color('red') | ||
except ValueError: | ||
pass | ||
else: | ||
raise AssertionError("No exception raised on out-of-bounds date") | ||
|
||
def test_set_invalid_string(self): | ||
class Q(param.Parameterized): | ||
q = param.Color() | ||
try: | ||
Q.q = 'red' | ||
except ValueError: | ||
pass | ||
else: | ||
raise AssertionError("No exception raised on out-of-bounds date") | ||
|
||
def test_valid_long_hex(self): | ||
class Q(param.Parameterized): | ||
q = param.Color() | ||
Q.q = '#ffffff' | ||
self.assertEqual(Q.q, '#ffffff') | ||
|
||
def test_valid_short_hex(self): | ||
class Q(param.Parameterized): | ||
q = param.Color() | ||
Q.q = '#fff' | ||
self.assertEqual(Q.q, '#fff') | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
""" | ||
Unit test for composite parameters. | ||
Originally implemented as doctests in Topographica in the file | ||
testCompositeParameter.txt | ||
""" | ||
|
||
import param | ||
from . import API1TestCase | ||
|
||
class TestCompositeParameters(API1TestCase): | ||
|
||
def setUp(self): | ||
super(TestCompositeParameters, self).setUp() | ||
# initialize a class with a compound parameter | ||
class A(param.Parameterized): | ||
x = param.Number(default=0) | ||
y = param.Number(default=0) | ||
xy = param.Composite(attribs=['x','y']) | ||
|
||
self.A = A | ||
self.a = self.A() | ||
|
||
class SomeSequence(object): | ||
"Can't use iter with Dynamic (doesn't pickle, doesn't copy)" | ||
def __init__(self,sequence): | ||
self.sequence=sequence | ||
self.index=0 | ||
def __call__(self): | ||
val=self.sequence[self.index] | ||
self.index+=1 | ||
return val | ||
|
||
self.SomeSequence = SomeSequence | ||
|
||
def test_initialization(self): | ||
"Make an instance and do default checks" | ||
self.assertEqual(self.a.x, 0) | ||
self.assertEqual(self.a.y, 0) | ||
self.assertEqual(self.a.xy, [0,0]) | ||
|
||
|
||
def test_set_component(self): | ||
self.a.x = 1 | ||
self.assertEqual(self.a.xy, [1,0]) | ||
|
||
def test_set_compound(self): | ||
self.a.xy = (2,3) | ||
self.assertEqual(self.a.x, 2) | ||
self.assertEqual(self.a.y, 3) | ||
|
||
def test_compound_class(self): | ||
" Get the compound on the class " | ||
self.assertEqual(self.A.xy, [0,0]) | ||
|
||
def test_set_compound_class_set(self): | ||
self.A.xy = (5,6) | ||
self.assertEqual(self.A.x, 5) | ||
self.assertEqual(self.A.y, 6) | ||
|
||
def test_set_compound_class_instance(self): | ||
self.A.xy = (5,6) | ||
# # Make a new instance | ||
b = self.A() | ||
self.assertEqual(b.x, 5) | ||
self.assertEqual(b.y, 6) | ||
|
||
def test_set_compound_class_instance_unchanged(self): | ||
self.a.xy = (2,3) | ||
self.A.xy = (5,6) | ||
self.assertEqual(self.a.x, 2) | ||
self.assertEqual(self.a.y, 3) | ||
|
||
def test_composite_dynamic(self): | ||
""" | ||
Check CompositeParameter is ok with Dynamic | ||
CB: this test is really of Parameterized. | ||
""" | ||
a2 = self.A(x=self.SomeSequence([1,2,3]), | ||
y=self.SomeSequence([4,5,6])) | ||
|
||
a2.x, a2.y # Call of x and y params | ||
# inspect should not advance numbers | ||
self.assertEqual(a2.param.inspect_value('xy'), [1, 4]) | ||
|
||
def test_composite_dynamic_generator(self): | ||
|
||
a2 = self.A(x=self.SomeSequence([1,2,3]), | ||
y=self.SomeSequence([4,5,6])) | ||
|
||
a2.x, a2.y # Call of x and y params | ||
ix,iy = a2.param.get_value_generator('xy') | ||
# get_value_generator() should give the objects | ||
self.assertEqual(ix(), 2) | ||
self.assertEqual(iy(), 5) | ||
|
||
|
||
if __name__ == "__main__": | ||
import nose | ||
nose.runmodule() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
""" | ||
Unit test for Date parameters. | ||
""" | ||
|
||
|
||
import datetime as dt | ||
import param | ||
from . import API1TestCase | ||
|
||
class TestDateParameters(API1TestCase): | ||
|
||
def test_initialization_out_of_bounds(self): | ||
try: | ||
class Q(param.Parameterized): | ||
q = param.Date(dt.datetime(2017,2,27), | ||
bounds=(dt.datetime(2017,2,1), | ||
dt.datetime(2017,2,26))) | ||
except ValueError: | ||
pass | ||
else: | ||
raise AssertionError("No exception raised on out-of-bounds date") | ||
|
||
def test_set_out_of_bounds(self): | ||
class Q(param.Parameterized): | ||
q = param.Date(bounds=(dt.datetime(2017,2,1), | ||
dt.datetime(2017,2,26))) | ||
try: | ||
Q.q = dt.datetime(2017,2,27) | ||
except ValueError: | ||
pass | ||
else: | ||
raise AssertionError("No exception raised on out-of-bounds date") | ||
|
||
def test_set_exclusive_out_of_bounds(self): | ||
class Q(param.Parameterized): | ||
q = param.Date(bounds=(dt.datetime(2017,2,1), | ||
dt.datetime(2017,2,26)), | ||
inclusive_bounds=(True, False)) | ||
try: | ||
Q.q = dt.datetime(2017,2,26) | ||
except ValueError: | ||
pass | ||
else: | ||
raise AssertionError("No exception raised on out-of-bounds date") | ||
|
||
def test_get_soft_bounds(self): | ||
q = param.Date(dt.datetime(2017,2,25), | ||
bounds=(dt.datetime(2017,2,1), | ||
dt.datetime(2017,2,26)), | ||
softbounds=(dt.datetime(2017,2,1), | ||
dt.datetime(2017,2,25))) | ||
self.assertEqual(q.get_soft_bounds(), (dt.datetime(2017,2,1), | ||
dt.datetime(2017,2,25))) | ||
|
Oops, something went wrong.