[pypy-svn] r50942 - pypy/dist/pypy/objspace/test

cfbolz at codespeak.net cfbolz at codespeak.net
Wed Jan 23 19:07:42 CET 2008


Author: cfbolz
Date: Wed Jan 23 19:07:41 2008
New Revision: 50942

Modified:
   pypy/dist/pypy/objspace/test/test_reflective.py
Log:
improve the autocurrying to work with keyword arguments


Modified: pypy/dist/pypy/objspace/test/test_reflective.py
==============================================================================
--- pypy/dist/pypy/objspace/test/test_reflective.py	(original)
+++ pypy/dist/pypy/objspace/test/test_reflective.py	Wed Jan 23 19:07:41 2008
@@ -120,12 +120,37 @@
             def __call__(self, *args, **kwargs):
                 args, kwargs = self.combine_args(args, kwargs)
                 return self.callable(*args, **kwargs)
+        def enough_args(func, args, kwargs):
+            code = func.func_code
+            needed = code.co_varnames[:code.co_argcount]
+            needed_set = set(needed)
+            argnames = set(needed)
+            defaults = func.func_defaults
+            has_varargs = bool(code.co_flags & 4)
+            for i in range(min(len(args), len(needed))):
+                name = needed[i]
+                needed_set.remove(name)
+            for key, value in kwargs.iteritems():
+                if key not in needed_set:
+                    if key not in argnames:
+                        raise TypeError(
+                            "%s() got an unexpected keyword argument %r" % (
+                                func.func_name, key))
+                    else:
+                        raise TypeError(
+                            "%s() got multiple values for keyword argument %r" % (
+                                func.func_name, key))
+                needed_set.remove(key)
+            if defaults is not None:
+                for i in range(len(defaults)):
+                    default_name = needed[-1 - i]
+                    needed_set.discard(default_name)
+            return len(needed_set) == 0
+
         import types
         class Space:
             def call_args(self, space, callable, *args, **kwargs):
                 print callable, args, kwargs
-                if len(kwargs) != 0: # XXX for now
-                    return space.call_args(callable, *args, **kwargs)
                 if isinstance(callable, partial):
                     args, kwargs = callable.combine_args(args, kwargs)
                     func = callable.func
@@ -141,12 +166,7 @@
                     return space.call_args(callable, *args, **kwargs)
                 else:
                     func = callable
-                defaults = func.func_defaults
-                if defaults is None:
-                    defaults = ()
-                argcount = func.func_code.co_argcount
-                minargs = argcount - len(defaults)
-                if len(args) >= minargs:
+                if enough_args(func, args, kwargs):
                     return space.call_args(callable, *args, **kwargs)
                 return partial(func, callable, *args, **kwargs)
         def f(x, y, z):
@@ -166,3 +186,6 @@
         a = A(3)
         assert a.func()(5, 6) == f(3, 5, 6)
         assert A.func()(a)(5)(6) == f(3, 5, 6)
+        def f(x, y=1):
+            return x + y * 2
+        f(y=2)(3) == 7



More information about the Pypy-commit mailing list