[Python-checkins] r53940 - sandbox/trunk/pep362/pep362.py sandbox/trunk/pep362/test_pep362.py
brett.cannon
python-checkins at python.org
Mon Feb 26 16:29:05 CET 2007
Author: brett.cannon
Date: Mon Feb 26 16:29:03 2007
New Revision: 53940
Modified:
sandbox/trunk/pep362/pep362.py
sandbox/trunk/pep362/test_pep362.py
Log:
Expand worst-case tests to thoroughly check every parameter. Also fix a
Signature.bind bug that was subsequently found.
This means the code finally works (both in 2.6 and 3.0).
Modified: sandbox/trunk/pep362/pep362.py
==============================================================================
--- sandbox/trunk/pep362/pep362.py (original)
+++ sandbox/trunk/pep362/pep362.py Mon Feb 26 16:29:03 2007
@@ -52,7 +52,23 @@
class Signature(object):
- """Object to represent the signature of a function/method."""
+ """Object to represent the signature of a function/method.
+
+ Attributes:
+ * parameters
+ Sequence of Parameter objects.
+ * name
+ Name of the function/method.
+ * var_args
+ Name of the variable positional parameter, else ''.
+ * var_kw_wargs
+ Name of the variable keywrod parameter, else ''.
+ * var_annotations
+ Dict keyed on the variable parameter names with the values of the
+ annotation for the parameter. If an annotation does not exist for a
+ parameter, the key does not exist.
+
+ """
def __init__(self, func):
"""Initialize from a function or method object."""
@@ -62,7 +78,7 @@
self.name = func.__name__
- argspec = getargspec(func)
+ argspec = getargspec(func) # Needed only for tuple parameters.
parameters = []
# Parameter information.
@@ -71,24 +87,25 @@
keyword_only_count = func_code.co_kwonlyargcount
else:
keyword_only_count = 0
- #positional = func_code.co_varnames[:pos_count]
positional = argspec[0]
- keyword_only = func_code.co_varnames[pos_count:keyword_only_count]
+ keyword_only = func_code.co_varnames[pos_count:
+ 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]):
+ name = self._convert_name(name)
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:]):
+ name = self._convert_name(name)
has_annotation, annotation = self._find_annotation(func, name)
default_value = func.func_defaults[offset]
param = Parameter(name, offset+non_default_count,
@@ -152,11 +169,11 @@
annotation = func.func_annotations[name]
return has_annotation, annotation
- def _list2tuple(self, list_):
- if not isinstance(list_, list):
- return list_
+ def _convert_name(self, name):
+ if not isinstance(name, list):
+ return name
else:
- return tuple(cls._list2tuple(x) for x in list_)
+ return tuple(self._convert_name(x) for x in name)
def bind(self, *args, **kwargs):
"""Return a dictionary mapping function arguments to their parameter
@@ -184,17 +201,18 @@
if not self.parameters and args and self.var_args:
bindings[self.var_args] = args
args = tuple()
- for index, position_arg in enumerate(args):
+ for index, position_arg in enumerate(args[:]):
try:
param = positional.pop(0)
except IndexError:
# *args.
if self.var_args:
- bindings[self.var_args] = tuple(args[index-1:])
+ bindings[self.var_args] = tuple(args)
break
else:
raise BindError("too many positional arguments")
self._tuple_bind(bindings, param.name, position_arg)
+ args = args[1:]
# Keyword arguments & default values.
else:
for positional_param in positional:
Modified: sandbox/trunk/pep362/test_pep362.py
==============================================================================
--- sandbox/trunk/pep362/test_pep362.py (original)
+++ sandbox/trunk/pep362/test_pep362.py Mon Feb 26 16:29:03 2007
@@ -44,6 +44,7 @@
self.failUnlessEqual(param.default_value, default_value)
param = pep362.Parameter('_', 0, False)
self.failUnlessEqual(param.has_default, False)
+ self.failUnless(not hasattr(param, 'default_value'))
def test_keyword_only(self):
# Setting the value for keyword_only should create an attribute.
@@ -110,7 +111,7 @@
self.failUnless(param.has_default)
self.failUnlessEqual(42, param.default_value)
- def XXX_test_parameter_tuple(self):
+ def 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 +122,7 @@
self.failUnless(not param.has_default)
self.failUnless(not hasattr(param, 'default_value'))
- def XXX_test_parameter_tuple_default(self):
+ def 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 +266,7 @@
self.failUnlessRaises(pep362.BindError, sig.bind, a=0, b=1)
self.failUnlessRaises(pep362.BindError, sig.bind, b=1)
- def XXX_test_tuple_parameter(self):
+ def test_tuple_parameter(self):
sig = pep362.Signature(pep362_fodder.tuple_args)
arg = (1, ((2,),))
binding = sig.bind(arg)
@@ -273,7 +274,7 @@
self.failUnlessRaises(pep362.BindError, sig.bind, (1,2,3))
self.failUnlessRaises(pep362.BindError, sig.bind, (1, 2))
- def XXX_test_default_tuple_parameter(self):
+ def test_default_tuple_parameter(self):
sig = pep362.Signature(pep362_fodder.default_tuple_args)
binding = sig.bind()
self.failUnlessEqual({'a':1, 'b':2}, binding)
@@ -281,8 +282,31 @@
binding = sig.bind(arg)
self.failUnlessEqual({'a':0, 'b':1}, binding)
- def XXX_test_all_parameter_types(self):
+ def test_all_args(self):
sig = pep362.Signature(pep362_fodder.all_args)
+ # a, (b, (c,)), d=0, (e, (f,))=(4, (5,)), *g, **h
+ # name, position, has_default, default value
+ expect = (('a', 0, False, None),
+ (('b', ('c',)), 1, False, None),
+ ('d', 2, True, 0),
+ (('e', ('f',)), 3, True, (4, (5,))))
+ self.failUnlessEqual(len(sig.parameters), len(expect))
+ for param, check in zip(sig.parameters, expect):
+ name, pos, has_default, default_value = check
+ self.failUnlessEqual(param.name, name)
+ self.failUnlessEqual(param.position, pos)
+ if has_default:
+ self.failUnless(param.has_default)
+ self.failUnlessEqual(param.default_value, default_value)
+ else:
+ self.failUnless(not param.has_default)
+ self.failUnless(not hasattr(param, 'default_value'))
+ self.failUnless(not param.keyword_only)
+ self.failUnless(not param.has_annotation)
+ self.failUnless(not hasattr(param, 'annotation'))
+ self.failUnlessEqual(sig.var_args, 'g')
+ self.failUnlessEqual(sig.var_kw_args, 'h')
+ self.failUnlessEqual(len(sig.var_annotations), 0)
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(),
'h':{'i':7}}
@@ -306,8 +330,46 @@
self.failUnlessRaises(pep362.BindError, sig.bind, 1)
@py3k_test
- def XXX_test_all_args(self):
+ def test_all_py3k_args(self):
+ # a, (b, (c,)), d=0, (e, (f,))=(0, (0,)), *args, g, h=8, **kwargs
sig = pep362.Signature(pep362_py3k_fodder.all_args)
+ # name, position, kw only, has_default, default, has anno, anno
+ expected = (('a', 0, False, False, None, True, int),
+ (('b', ('c',)), 1, False, False, None, False, None),
+ ('d', 2, False, True, 0, False, None),
+ (('e', ('f',)), 3, False, True, (0, (0,)), False, None),
+ ('g', 4, True, False, None, True, int),
+ ('h', 5, True, True, 8, True, int))
+ self.failUnlessEqual(len(sig.parameters), len(expected),
+ "len(%r) != len(%r)" % ([param.name
+ for param in sig.parameters],
+ [expect[0] for expect in expected]))
+ for param, check in zip(sig.parameters, expected):
+ name, pos, kw_only, has_default, default, has_anno, anno = check
+ self.failUnlessEqual(param.name, name)
+ self.failUnlessEqual(param.position, pos)
+ if kw_only:
+ self.failUnless(param.keyword_only)
+ else:
+ self.failUnless(not param.keyword_only)
+ if has_default:
+ self.failUnless(param.has_default)
+ self.failUnlessEqual(param.default_value, default)
+ else:
+ self.failUnless(not param.has_default)
+ self.failUnless(not hasattr(param, 'default_value'))
+ if has_anno:
+ self.failUnless(param.has_annotation)
+ self.failUnlessEqual(param.annotation, anno)
+ else:
+ self.failUnless(not param.has_annotation)
+ self.failUnless(not hasattr(param, 'annotation'))
+ self.failUnlessEqual(sig.var_args, 'args')
+ self.failUnless(sig.var_args in sig.var_annotations)
+ self.failUnlessEqual(sig.var_annotations[sig.var_args], int)
+ self.failUnlessEqual(sig.var_kw_args, 'kwargs')
+ self.failUnless(sig.var_kw_args in sig.var_annotations)
+ self.failUnlessEqual(sig.var_annotations[sig.var_kw_args], int)
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,
'args':(6,), 'kwargs':{'i':9}}
More information about the Python-checkins
mailing list