Bumped to version 0.3, adding translated functionality. 0.3
authorW. Trevor King <wking@drexel.edu>
Thu, 25 Jun 2009 19:05:04 +0000 (15:05 -0400)
committerW. Trevor King <wking@drexel.edu>
Thu, 25 Jun 2009 19:19:38 +0000 (15:19 -0400)
Now you can rename kwargs in parent functions.  This is useful
if some kwarg name is perfectly clear for the child function,
but needs a bit more context in the parent.  For example if
  vibrate(time)
is a child of
  calibrate(vibration_time)
you'd want to translate "time"->"vibration_time" somewehere
in between.  See the doc strings for explicit examples.

.be/bugs/05b1f110-85b5-4373-9378-07f54c7d316a/values
splittable_kwargs.py

index 1ce2b494d686ff28f26d8d1c6349170e496bffe9..5eff05c55193096112865edecdc43c3c0ef6ce74 100644 (file)
@@ -7,7 +7,7 @@ reporter: W. Trevor King <wking@drexel.edu>
 severity: minor
 
 
-status: open
+status: closed
 
 
 summary: Should have a map to translate kwarg names
index 0d870952c0965139da79114ce4a8a3709af8fd6a..04408a20b7530de636009ece735e18a52bd35e1a 100755 (executable)
@@ -9,7 +9,6 @@ This code is released to the public domain.
 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"
@@ -17,20 +16,18 @@ Example usage (adapted from the unittests)
     >>> @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
@@ -44,8 +41,10 @@ define baz) with
 
 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
@@ -62,19 +61,19 @@ something like
     ...     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):
@@ -90,49 +89,54 @@ class UnknownKwarg (KeyError):
 
 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:
@@ -140,18 +144,27 @@ def _kwargs(self):
                 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)
 
@@ -184,10 +197,11 @@ def _bar(a, b, c=2):
     "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)
@@ -258,7 +272,7 @@ bar: a 4, b 5, c 2
     def testDoubleLevel(self):
         deeper_joint = SplittableKwargsTestCase.deeper_joint
         expected = """joining
-  b : 5
+  b_bar : 5
   d : 6
   x : 1
   y : 2
@@ -267,7 +281,7 @@ foo: x 1, y 2, z 3
 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):