diff --git a/tests/pipeline/test_term.py b/tests/pipeline/test_term.py index 502d6e48..797c95eb 100644 --- a/tests/pipeline/test_term.py +++ b/tests/pipeline/test_term.py @@ -27,6 +27,7 @@ from zipline.pipeline.data.testing import TestingDataSet from zipline.pipeline.term import AssetExists, NotSpecified from zipline.pipeline.expression import NUMEXPR_MATH_FUNCS from zipline.testing import parameter_space +from zipline.testing.predicates import assert_equal, assert_raises from zipline.utils.numpy_utils import ( bool_dtype, categorical_dtype, @@ -358,20 +359,20 @@ class ObjectIdentityTestCase(TestCase): method = getattr(f, funcname) self.assertIs(method(), method()) + class SomeFactorParameterized(SomeFactor): + params = ('a', 'b') + def test_parameterized_term(self): - class SomeFactorParameterized(SomeFactor): - params = ('a', 'b') - - f = SomeFactorParameterized(a=1, b=2) + f = self.SomeFactorParameterized(a=1, b=2) self.assertEqual(f.params, {'a': 1, 'b': 2}) - g = SomeFactorParameterized(a=1, b=3) - h = SomeFactorParameterized(a=2, b=2) + g = self.SomeFactorParameterized(a=1, b=3) + h = self.SomeFactorParameterized(a=2, b=2) self.assertDifferentObjects(f, g, h) - f2 = SomeFactorParameterized(a=1, b=2) - f3 = SomeFactorParameterized(b=2, a=1) + f2 = self.SomeFactorParameterized(a=1, b=2) + f3 = self.SomeFactorParameterized(b=2, a=1) self.assertSameObject(f, f2, f3) self.assertEqual(f.params['a'], 1) @@ -379,6 +380,33 @@ class ObjectIdentityTestCase(TestCase): self.assertEqual(f.window_length, SomeFactor.window_length) self.assertEqual(f.inputs, tuple(SomeFactor.inputs)) + def test_parameterized_term_non_hashable_arg(self): + with assert_raises(TypeError) as e: + self.SomeFactorParameterized(a=[], b=1) + assert_equal( + str(e.exception), + "SomeFactorParameterized expected a hashable value for parameter" + " 'a', but got [] instead.", + ) + + with assert_raises(TypeError) as e: + self.SomeFactorParameterized(a=1, b=[]) + assert_equal( + str(e.exception), + "SomeFactorParameterized expected a hashable value for parameter" + " 'b', but got [] instead.", + ) + + with assert_raises(TypeError) as e: + self.SomeFactorParameterized(a=[], b=[]) + assert_equal( + str(e.exception), + "SomeFactorParameterized expected a hashable value for parameter" + " 'a', but got [] instead.", + ) + + + def test_bad_input(self): class SomeFactor(Factor): diff --git a/zipline/pipeline/term.py b/zipline/pipeline/term.py index 1bffc3e7..389be97b 100644 --- a/zipline/pipeline/term.py +++ b/zipline/pipeline/term.py @@ -129,8 +129,7 @@ class Term(with_metaclass(ABCMeta, object)): value = kwargs.pop(key) # Check here that the value is hashable so that we fail here # instead of trying to hash the param values tuple later. - hash(key) - param_values.append(value) + hash(value) except KeyError: raise TypeError( "{typename} expected a keyword parameter {name!r}.".format( @@ -148,6 +147,8 @@ class Term(with_metaclass(ABCMeta, object)): value=value, ) ) + + param_values.append(value) return tuple(zip(cls.params, param_values)) @staticmethod @@ -240,7 +241,7 @@ class Term(with_metaclass(ABCMeta, object)): if hasattr(self, name): raise TypeError( "Parameter {name!r} conflicts with already-present" - "attribute with value {value!r}.".format( + " attribute with value {value!r}.".format( name=name, value=getattr(self, name), )