[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