Added better error handling to _kwargs() and added doctests. 0.2
authorW. Trevor King <wking@drexel.edu>
Wed, 20 May 2009 17:33:00 +0000 (13:33 -0400)
committerW. Trevor King <wking@drexel.edu>
Wed, 20 May 2009 17:33:00 +0000 (13:33 -0400)
The docstring examples were close, and it's not good to get out-of-date.

splittable_kwargs.py

index 732ad373d8562bf41698562261b69a9338833ac0..0d870952c0965139da79114ce4a8a3709af8fd6a 100755 (executable)
@@ -1,46 +1,81 @@
 #!/usr/bin/python
 """
 splittable_kwargs allows the splitting of **kwargs arguments among
-several functions.  This
+several functions.
 
-Copyright (C)  W. Trevor King  2008
+Copyright (C)  W. Trevor King  2008, 2009
 This code is released to the public domain.
 
 Example usage (adapted from the unittests)
 
-  @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'))
-  def baz(d, **kwargs):
-      string = bar(c=4, **kwargs)
-      return string + "baz: d "+str(d)+"\n"
-  
-  @splittableKwargsFunction(foo, bar)
-  def simple_joint(**kwargs):
-      fookw,bazkw = simple_joint._splitargs(simple_joint, kwargs)
-      string = foo(**fookw)
-      string += baz(**bazkw)
-      return string
-  
-  simple_joint(y=3,c=1,d=5)
+    >>> 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'))
+    ... def baz(d, **kwargs):
+    ...     string = bar(a=5, c=4, **kwargs)
+    ...     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)
+    foo: x 1, y 3, z 2
+    bar: a 5, b 6, c 4
+    baz: d 7
 
 If, say, simple_joint's children had not been defined (you wanted to
-define bar after simple_joint in your module), you can skip the
+define baz after simple_joint in your module), you can skip the
 decorator in simple_joint, and make it splittable later (after you
-define bar) with
+define baz) with
 
-  make_splittable_kwargs_function(simple_joint, foo, bar)
+   make_splittable_kwargs_function(simple_joint, foo, baz)
+
+You can also get a list of the available named arguments with
+
+    >>> simple_joint._kwargs(simple_joint)
+    ['x', 'y', 'z', 'd', 'b', '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
+_function_, not a class instance.  If it really bothers you, try
+something like
+
+    >>> class ClassJoint (object):
+    ...     @splittableKwargsFunction(foo, baz)
+    ...     def __call__(self, **kwargs):
+    ...         fookw,bazkw = simple_joint._splitargs(simple_joint, kwargs)
+    ...         string = foo(**fookw)
+    ...         string += baz(**bazkw)
+    ...         return string.strip()
+    ...     def _kwargs(self):
+    ...         return self.__call__._kwargs(self.__call__)
+    >>> cj = ClassJoint()
+    >>> print cj(x=1,y=3,b=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"
+
 class UnknownKwarg (KeyError):
     def __init__(self, fn, kwarg, value):
         if hasattr(fn, "_kwargs"):
@@ -100,7 +135,11 @@ def _kwargs(self):
             child,masked = _parse_splittable(child)
             child_args = child._kwargs(child)
             for arg in masked:
-                child_args.remove(arg)
+                try:
+                    child_args.remove(arg)
+                except ValueError, e:
+                    msg = "%s not in %s" % (arg, child_args)
+                    raise ValueError(msg)
             args.extend(child_args)
     return args
 
@@ -247,6 +286,7 @@ if __name__ == "__main__":
     
     unitsuite = unittest.TestLoader().loadTestsFromTestCase( \
                                                       SplittableKwargsTestCase)
+    unitsuite.addTest(doctest.DocTestSuite())
     result = unittest.TextTestRunner(verbosity=2).run(unitsuite)
     numErrors = len(result.errors)
     numFailures = len(result.failures)