Example usage (adapted from the unittests)
>>> from splittable_kwargs import *
- >>>
>>> @splittableKwargsFunction()
... def foo(x, y, z=2):
... return "foo: x "+str(x)+", y "+str(y)+", z "+str(z)+"\\n"
>>> @splittableKwargsFunction()
... def bar(a, b, c=2):
... return "bar: a "+str(a)+", b "+str(b)+", c "+str(c)+"\\n"
- >>>
- >>> @splittableKwargsFunction((bar, 'a'))
+ >>> @splittableKwargsFunction({'fn':bar, 'mask':'a', 'translate':{'b':'b_bar'}})
... def baz(d, **kwargs):
- ... string = bar(a=5, c=4, **kwargs)
+ ... barkw, = baz._splitargs(baz, kwargs) # for translation/masking
+ ... string = bar(a=5, c=4, **barkw)
... return string + "baz: d "+str(d)+"\\n"
- >>>
>>> @splittableKwargsFunction(foo, baz)
... def simple_joint(**kwargs):
... fookw,bazkw = simple_joint._splitargs(simple_joint, kwargs)
... string = foo(**fookw)
... string += baz(**bazkw)
... return string.strip()
- >>>
- >>> print simple_joint(x=1,y=3,b=6,d=7)
+ >>> print simple_joint(x=1,y=3,b_bar=6,d=7)
foo: x 1, y 3, z 2
bar: a 5, b 6, c 4
baz: d 7
You can also get a list of the available named arguments with
+ >>> print baz._kwargs(baz)
+ ['d', 'b_bar', 'c']
>>> simple_joint._kwargs(simple_joint)
- ['x', 'y', 'z', 'd', 'b', 'c']
+ ['x', 'y', 'z', 'd', 'b_bar', 'c']
It may seem redundant to need to pass the function (here simple_joint)
to a method of simple_joint, but remember that simple_joint is a
... def _kwargs(self):
... return self.__call__._kwargs(self.__call__)
>>> cj = ClassJoint()
- >>> print cj(x=1,y=3,b=6,d=7)
+ >>> cj._kwargs()
+ ['self', 'x', 'y', 'z', 'd', 'b_bar', 'c']
+ >>> print cj(x=1,y=3,b_bar=6,d=7)
foo: x 1, y 3, z 2
bar: a 5, b 6, c 4
baz: d 7
- >>> cj._kwargs()
- ['self', 'x', 'y', 'z', 'd', 'b', 'c']
"""
import inspect
import doctest
import unittest
-VERSION = "0.2"
+VERSION = "0.3"
class UnknownKwarg (KeyError):
def __init__(self, fn, kwarg, value):
def _parse_splittable(splittable):
"""
- splittable -> (splittable_fn, masked_args)
+ splittable -> (splittable_fn, masked_args, translated_args)
"""
if hasattr(splittable, "_kwargs"): # bare splittableKwargsFunction
- return (splittable, [])
- else: # function followed by masked args
- return (splittable[0], splittable[1:])
+ return (splittable, [], {})
+ else: # masked/translated dict
+ return (splittable['fn'],
+ splittable.get('mask', []),
+ splittable.get('translate', {}))
def splitargs(kwargs, *internal_splittables):
"""
where
- *internal_splittables : a list of splittableKwargsFunctions items
- that this function uses internally.
- the items can be either
- a bare splittableKwargsFunction
- or a tuple where the additional elements are arguments to mask
- a (bare splittableKwargsFunction, masked argument, ...)
+ *internal_splittables : a list of splittableKwargsFunctions
+ items that this function uses internally. The items must be
+ parsable by _parse_splittable().
"""
# sort the kwargs according to the appropriate function
fn_kwargs = [{} for splittable in internal_splittables]
for key,value in kwargs.items():
sorted = False
for i,splittable in enumerate(internal_splittables):
- fn,masked = _parse_splittable(splittable)
- if key in fn._kwargs(fn) and key not in masked:
- fn_kwargs[i][key] = value
+ fn,masked,translated = _parse_splittable(splittable)
+ inv_translation = dict([(v,k) for k,v in translated.items()])
+ if key in inv_translation:
+ child_key = inv_translation[key]
sorted = True
+ elif key in fn._kwargs(fn) and key not in masked:
+ child_key = key
+ sorted = True
+ if sorted == True:
+ fn_kwargs[i][child_key] = value
break
- if sorted != True:
+ if sorted != True: # couldn't find anywhere for that key.
fns = []
for splittable in internal_splittables:
- fn,masked = _parse_splittable(splittable)
+ fn,masked,translated = _parse_splittable(splittable)
fns.append(fn)
raise UnknownKwarg(fns, key, value)
return fn_kwargs
def _kwargs(self):
- "return a list of acceptable kwargs"
+ "Return a list of acceptable kwargs"
args,varargs,varkw,defaults = inspect.getargspec(self)
if varargs != None:
raise NotImplementedError, "\n %s" % varargs
if varkw != None:
for child in self._childSplittables:
- child,masked = _parse_splittable(child)
+ child,masked,translated = _parse_splittable(child)
child_args = child._kwargs(child)
for arg in masked:
try:
except ValueError, e:
msg = "%s not in %s" % (arg, child_args)
raise ValueError(msg)
+ for original,new in translated.items():
+ try:
+ child_args[child_args.index(original)] = new
+ except ValueError, e:
+ msg = "%s not in %s" % (arg, child_args)
+ raise ValueError(msg)
args.extend(child_args)
return args
def _declareInternalSplittableKwargsFunction(self, function):
"""
- FUNCTION can be either a bare splittableKwargsFuntion or one
- such function followed by a sequence of masked arguments.
+ FUNCTION can be either a bare splittableKwargsFuntion or a dict of
+ the form:
+ {'fn': splittableKwargsFuntion,
+ 'mask':["argumentA",...],
+ 'translate':{"argumentB":"argB_new_name", ...}}
Example values for FUNCTION:
- bar
- (bar, "a")
- (bar, "a", "b")
+ bar
+ {'fn':bar, mask:["a"]}
+ {'fn':bar, mask:["a", "b"], translate:{"c":"bar_c"}}}
"""
self._childSplittables.append(function)
"bar function"
return "bar: a "+str(a)+", b "+str(b)+", c "+str(c)+"\n"
-@splittableKwargsFunction((_bar, 'a'))
+@splittableKwargsFunction({'fn':_bar, 'mask':'a', 'translate':{'b':'b_bar'}})
def _baz(d, **kwargs):
"baz function"
- string = _bar(a=6, c=4, **kwargs)
+ barkw, = _baz._splitargs(_baz, kwargs) # for translation/masking
+ string = _bar(a=6, c=4, **barkw)
return string + "baz: d "+str(d)+"\n"
@splittableKwargsFunction(_foo, _bar)
def testDoubleLevel(self):
deeper_joint = SplittableKwargsTestCase.deeper_joint
expected = """joining
- b : 5
+ b_bar : 5
d : 6
x : 1
y : 2
bar: a 6, b 5, c 4
baz: d 6
"""
- output = deeper_joint(x=1, y=2, z=3, b=5, d=6)
+ output = deeper_joint(x=1, y=2, z=3, b_bar=5, d=6)
self.failUnless(output == expected,
"GOT\n%s\nEXPECTED\n%s" % (output, expected))
def testDoubleLevelOverrideRequired(self):