mirror of
https://github.com/wassname/catalyst.git
synced 2026-07-15 11:22:18 +08:00
ENH: adds optionally for preprocessors
This commit is contained in:
@@ -17,6 +17,7 @@ from zipline.utils.input_validation import (
|
||||
expect_dtypes,
|
||||
expect_types,
|
||||
optional,
|
||||
optionally,
|
||||
)
|
||||
|
||||
|
||||
@@ -347,3 +348,22 @@ class PreprocessTestCase(TestCase):
|
||||
# test invalid timezone strings
|
||||
for tz in invalid:
|
||||
self.assertRaises(pytz.UnknownTimeZoneError, f, tz)
|
||||
|
||||
def test_optionally(self):
|
||||
error = TypeError('arg must be int')
|
||||
|
||||
def preprocessor(func, argname, arg):
|
||||
if not isinstance(arg, int):
|
||||
raise error
|
||||
return arg
|
||||
|
||||
@preprocess(a=optionally(preprocessor))
|
||||
def f(a):
|
||||
return a
|
||||
|
||||
self.assertIs(f(1), 1)
|
||||
self.assertIsNone(f(None))
|
||||
|
||||
with self.assertRaises(TypeError) as e:
|
||||
f('a')
|
||||
self.assertIs(e.exception, error)
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
from datetime import tzinfo
|
||||
from functools import partial
|
||||
from functools import partial, wraps
|
||||
from operator import attrgetter
|
||||
|
||||
from numpy import dtype
|
||||
@@ -24,6 +24,46 @@ import toolz.curried.operator as op
|
||||
from zipline.utils.preprocess import preprocess
|
||||
|
||||
|
||||
def optionally(preprocessor):
|
||||
"""Modify a preprocessor to explicitly allow `None`.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
preprocessor : callable[callable, str, any -> any]
|
||||
A preprocessor to delegate to when `arg is not None`.
|
||||
|
||||
Returns
|
||||
-------
|
||||
optional_preprocessor : callable[callable, str, any -> any]
|
||||
A preprocessor that delegates to `preprocessor` when `arg is not None`.
|
||||
|
||||
Usage
|
||||
-----
|
||||
>>> def preprocessor(func, argname, arg):
|
||||
... if not isinstance(arg, int):
|
||||
... raise TypeError('arg must be int')
|
||||
... return arg
|
||||
...
|
||||
>>> @preprocess(a=optionally(preprocessor))
|
||||
... def f(a):
|
||||
... return a
|
||||
...
|
||||
>>> f(1) # call with int
|
||||
1
|
||||
>> f('a') # call with not int
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
TypeError: arg must be int
|
||||
>>> f(None) # call with explicit None
|
||||
None
|
||||
"""
|
||||
@wraps(preprocessor)
|
||||
def wrapper(func, argname, arg):
|
||||
return arg if arg is None else preprocessor(func, argname, arg)
|
||||
|
||||
return wrapper
|
||||
|
||||
|
||||
def ensure_upper_case(func, argname, arg):
|
||||
if isinstance(arg, string_types):
|
||||
return arg.upper()
|
||||
|
||||
Reference in New Issue
Block a user