[Python-checkins] r53924 - sandbox/trunk/pep362/pep362.py sandbox/trunk/pep362/pep362_py3k_fodder.py sandbox/trunk/pep362/test_pep362.py

brett.cannon python-checkins at python.org
Sun Feb 25 23:57:12 CET 2007


Author: brett.cannon
Date: Sun Feb 25 23:57:08 2007
New Revision: 53924

Modified:
   sandbox/trunk/pep362/pep362.py
   sandbox/trunk/pep362/pep362_py3k_fodder.py
   sandbox/trunk/pep362/test_pep362.py
Log:
Rewrite Signature.__init__ since 'inspect' cannot handle keyword-only
arguments.  This means that tuples are once again not supported (at the
moment).


Modified: sandbox/trunk/pep362/pep362.py
==============================================================================
--- sandbox/trunk/pep362/pep362.py	(original)
+++ sandbox/trunk/pep362/pep362.py	Sun Feb 25 23:57:08 2007
@@ -1,5 +1,4 @@
-import inspect
-
+from inspect import getargspec
 
 class BindError(TypeError):
     """Represent a failure of inspect.Signature.bind() being able to to
@@ -50,22 +49,21 @@
             self.has_annotation = True
             self.annotation = annotation
 
-    @classmethod
-    def __tuple2param(self, tuple_):
+    def _tuple2param(self, tuple_):
         if not isinstance(tuple_, tuple):
             return str(tuple_)
         elif len(tuple_) == 1:
             return "(" + str(tuple_[0]) +",)"
         else:
             return ('(' +
-                    ', '.join(self.__tuple2param(x) for  x in tuple_) +
+                    ', '.join(self._tuple2param(x) for  x in tuple_) +
                     ')')
 
     def __str__(self):
         """Return the string representation of the parameter as it would look
         in a function's signature."""
         if isinstance(self.name, tuple):
-            result = self.__tuple2param(self.name)
+            result = self._tuple2param(self.name)
         else:
             result = self.name
         if self.has_default:
@@ -85,58 +83,75 @@
 
         self.name = func.__name__
 
-        argspec = inspect.getargspec(func)
-
-        # Variable parameters.
-        self.var_args = argspec[1] if (argspec[1] is not None)  else ''
-        self.var_kw_args = argspec[2] if (argspec[2] is not None) else ''
-        self.var_annotations = {}
-        for var_arg in (self.var_args, self.var_kw_args):
-            if var_arg in func.func_annotations:
-                self.var_annotations[var_arg] = func.func_annotations[var_arg]
-
-        # Non-keyword-only arguments.
-        arg_count = len(argspec[0])
-        defaults_start = (arg_count - len(argspec[3])
-                            if argspec[3] else arg_count)
+        argspec = getargspec(func)
         parameters = []
-        for index, arg_name in enumerate(argspec[0]):
-            kwargs = dict.fromkeys(('has_default', 'default_value',
-            'has_annotation', 'annotation'), False)
-            if isinstance(arg_name, list):
-                arg_name = self.__list2tuple(arg_name)
-
-            # Default values.
-            if index >= defaults_start:
-                kwargs['has_default'] = True
-                kwargs['default_value'] = argspec[3][index - defaults_start]
-            # Parameter annotations.
-            if hasattr(func, 'func_annotations'):
-                if arg_name in func.func_annotations:
-                    kwargs['has_annotation'] = True
-                    kwargs['annotation'] = func.func_annotations[arg_name]
-            param = Parameter(arg_name, index, **kwargs)
-            parameters.append(param)
 
-        # Keyword-only arguments.
+        # Parameter information.
+        pos_count = func_code.co_argcount
         if hasattr(func_code, 'co_kwonlyargcount'):
-            non_keyword_count = func_code.co_argcount
-            keyword_count = func_code.co_kwonlyargcount
-            keyword_only_params = func_code.co_varnames[non_keyword_count:
-                                            (non_keyword_count+keyword_count)]
-            for index, param_name in enumerate(keyword_only_params):
-                kwargs = dict.fromkeys(('has_default', 'default_value',
-                'has_annotation', 'annotation'), False)
-                # Default values.
-                if func.func_kwdefaults and param_name in func.func_kwdefaults:
-                    kwargs['has_default'] = True
-                    kwargs['default_value'] = func.func_kwdefaults[param_name]
-                if param_name in func.func_annotations:
-                    kwargs['has_annotation'] = True
-                    kwargs['annotation'] = func.func_annotations[param_name]
-                parameters.append(Parameter(param_name,
-                                            index+non_keyword_count,
-                                            keyword_only=True, **kwargs))
+            keyword_only_count = func_code.co_kwonlyargcount
+        else:
+            keyword_only_count = 0
+        positional = func_code.co_varnames[:pos_count]
+        keyword_only = func_code.co_varnames[pos_count:keyword_only_count]
+        if func.func_defaults:
+            pos_default_count = len(func.func_defaults)
+        else:
+            pos_default_count = 0
+
+        # XXX Use inspect where tuple parameters are possible.
+        # Non-keyword-only parameters w/o defaults.
+        non_default_count = pos_count - pos_default_count
+        for index, name in enumerate(positional[:non_default_count]):
+            has_annotation, annotation = self._find_annotation(func, name)
+            param = Parameter(name, index, has_default=False,
+                    has_annotation=has_annotation, annotation=annotation)
+            parameters.append(param)
+        # ... w/ defaults.
+        for offset, name in enumerate(positional[non_default_count:]):
+            has_annotation, annotation = self._find_annotation(func, name)
+            default_value = func.func_defaults[offset]
+            param = Parameter(name, offset+non_default_count,
+                                has_default=True, default_value=default_value,
+                                has_annotation=has_annotation,
+                                annotation=annotation)
+            parameters.append(param)
+        # Keyword-only parameters.
+        for offset, name in enumerate(keyword_only):
+            has_annotation, annotation = self._find_annotation(func, name)
+            has_default, default_value = False, None
+            if func.func_kwdefaults and name in func.func_kwdefaults:
+                has_default = True
+                default_value = func.func_kwdefaults[name]
+            param = Parameter(name, offset+pos_count, keyword_only=True,
+                                has_default=has_default,
+                                default_value=default_value,
+                                has_annotation=has_annotation,
+                                annotation=annotation)
+            parameters.append(param)
+        # Variable parameters.
+        index = pos_count + keyword_only_count
+        self.var_annotations = dict()
+        if func_code.co_flags & 0x04:
+            self.var_args = func_code.co_varnames[index]
+            has_annotation, annotation = self._find_annotation(func,
+                                                                self.var_args)
+            if has_annotation:
+                self.var_annotations[self.var_args] = (
+                                        func.func_annotations[self.var_args])
+            index += 1
+        else:
+            self.var_args = ''
+        if func_code.co_flags & 0x08:
+            self.var_kw_args = func_code.co_varnames[index]
+            has_annotation, annotation = self._find_annotation(func,
+                                                                self.var_args)
+            if has_annotation:
+                self.var_annotations[self.var_kw_args] = (
+                                    func.func_annotations[self.var_kw_args])
+            index += 1
+        else:
+            self.var_kw_args = ''
 
         self.parameters = tuple(parameters)
 
@@ -147,12 +162,21 @@
                 self.has_annotation = True
                 self.annotation = func.func_annotations['return']
 
-    @classmethod
-    def __list2tuple(cls, list_):
+    def _find_annotation(self, func, name):
+        """Return True if an annotation exists for the named parameter along
+        with its annotation, else return False and None."""
+        has_annotation, annotation = False, None
+        if hasattr(func, 'func_annotations'):
+            if name in func.func_annotations:
+                has_annotation = True
+                annotation = func.func_annotations[name]
+        return has_annotation, annotation
+
+    def _list2tuple(self, list_):
         if not isinstance(list_, list):
             return list_
         else:
-            return tuple(cls.__list2tuple(x) for x in list_)
+            return tuple(cls._list2tuple(x) for x in list_)
 
     def __str__(self):
         """String representation of a signature as one might write it in source
@@ -233,15 +257,15 @@
                                 % key)
             if key in positional_dict:
                 del positional_dict[key]
+            # Keyword-only.
             elif key in keyword_only:
                 del keyword_only[key]
+            # **kwargs.
+            elif self.var_kw_args:
+                    bindings[self.var_kw_args][key] = value
+                    continue
             else:
-                # **kwargs.
-                if self.var_kw_args:
-                    bindings[self.var_kw_args] = kwargs
-                    break
-                else:
-                    raise BindError("too many keyword arguments")
+                raise BindError("too many keyword arguments")
             bindings[key] = value
             del kwargs[key]
         # Keyword-only default values.

Modified: sandbox/trunk/pep362/pep362_py3k_fodder.py
==============================================================================
--- sandbox/trunk/pep362/pep362_py3k_fodder.py	(original)
+++ sandbox/trunk/pep362/pep362_py3k_fodder.py	Sun Feb 25 23:57:08 2007
@@ -21,4 +21,4 @@
 
 def all_args(a:int, (b, (c,)), d=0, (e, (f,))=(0, (0,)), *args:int,
                 g:int, h:int=8, **kwargs:int) -> int:
-    pass
+    return a, b, c, d, e, f, g, h, args, kwargs

Modified: sandbox/trunk/pep362/test_pep362.py
==============================================================================
--- sandbox/trunk/pep362/test_pep362.py	(original)
+++ sandbox/trunk/pep362/test_pep362.py	Sun Feb 25 23:57:08 2007
@@ -110,7 +110,7 @@
         self.failUnless(param.has_default)
         self.failUnlessEqual(42, param.default_value)
 
-    def test_parameter_tuple(self):
+    def XXX_test_parameter_tuple(self):
         # A function with a tuple as a parameter should work.
         sig = pep362.Signature(pep362_fodder.tuple_args)
         self.failUnlessEqual('tuple_args', sig.name)
@@ -121,7 +121,7 @@
         self.failUnless(not param.has_default)
         self.failUnless(not hasattr(param, 'default_value'))
 
-    def test_parameter_tuple_default(self):
+    def XXX_test_parameter_tuple_default(self):
         # A default argument for a tuple parameter needs to work.
         sig = pep362.Signature(pep362_fodder.default_tuple_args)
         self.failUnlessEqual('default_tuple_args', sig.name)
@@ -265,7 +265,7 @@
         self.failUnlessRaises(pep362.BindError, sig.bind, a=0, b=1)
         self.failUnlessRaises(pep362.BindError, sig.bind, b=1)
 
-    def test_tuple_parameter(self):
+    def XXX_test_tuple_parameter(self):
         sig = pep362.Signature(pep362_fodder.tuple_args)
         arg = (1, ((2,),))
         binding = sig.bind(arg)
@@ -273,7 +273,7 @@
         self.failUnlessRaises(pep362.BindError, sig.bind, (1,2,3))
         self.failUnlessRaises(pep362.BindError, sig.bind, (1, 2))
 
-    def test_default_tuple_parameter(self):
+    def XXX_test_default_tuple_parameter(self):
         sig = pep362.Signature(pep362_fodder.default_tuple_args)
         binding = sig.bind()
         self.failUnlessEqual({'a':1, 'b':2}, binding)
@@ -281,7 +281,7 @@
         binding = sig.bind(arg)
         self.failUnlessEqual({'a':0, 'b':1}, binding)
 
-    def test_all_parameter_types(self):
+    def XXX_test_all_parameter_types(self):
         sig = pep362.Signature(pep362_fodder.all_args)
         binding = sig.bind(0, (1, (2,)), d=3, i=7)
         expected = {'a':0, 'b':1, 'c':2, 'd':3, 'e':4, 'f':5, 'g':tuple(),
@@ -306,11 +306,11 @@
         self.failUnlessRaises(pep362.BindError, sig.bind, 1)
 
     @py3k_test
-    def test_all_args(self):
+    def XXX_test_all_args(self):
         sig = pep362.Signature(pep362_py3k_fodder.all_args)
         binding = sig.bind(0, (1, (2,)), 3, (4, (5,)), 6, g=7, i=9)
         expected = {'a':0, 'b':1, 'c':2, 'd':3, 'e':4, 'f':5, 'g':7, 'h':8,
-                'i':9, 'args':(6,)}
+                'args':(6,), 'kwargs':{'i':9}}
         self.failUnlessEqual(binding, expected)
 
     def test_too_many_arguments(self):


More information about the Python-checkins mailing list