Index: Lib/test/test_inspect.py |
=================================================================== |
--- Lib/test/test_inspect.py (revision 79248) |
+++ Lib/test/test_inspect.py (working copy) |
@@ -1,3 +1,4 @@ |
+import re |
import sys |
import types |
import unittest |
@@ -3,4 +4,6 @@ |
import inspect |
import datetime |
+from UserList import UserList |
+from UserDict import UserDict |
from test.test_support import run_unittest, check_py3k_warnings |
@@ -557,10 +560,199 @@ |
self.assertIn(('m1', 'method', D), attrs, 'missing plain method') |
self.assertIn(('datablob', 'data', A), attrs, 'missing data') |
+class TestGetcallargsFunctions(unittest.TestCase): |
+ |
+ # tuple parameters are named '.1', '.2', etc. |
+ is_tuplename = re.compile(r'^\.\d+$').match |
+ |
+ def assertEqualCallArgs(self, func, call_params_string, locals=None): |
+ locals = dict(locals or {}, func=func) |
+ r1 = eval('func(%s)' % call_params_string, None, locals) |
+ r2 = eval('inspect.getcallargs(func, %s)' % call_params_string, None, locals) |
+ self.assertEqual(r1, r2) |
+ |
+ def assertEqualException(self, func, call_param_string, locals=None): |
+ locals = dict(locals or {}, func=func) |
+ try: |
+ eval('func(%s)' % call_param_string, None, locals) |
+ except Exception, ex1: |
+ pass |
+ else: |
+ self.fail('Exception not raised') |
+ try: |
+ eval('inspect.getcallargs(func, %s)' % call_param_string, None, locals) |
+ except Exception, ex2: |
+ pass |
+ else: |
+ self.fail('Exception not raised') |
+ self.assertEqual(str(ex1), str(ex2)) |
+ |
+ def makeCallable(self, signature): |
+ # create a function that returns its locals(), excluding the autogenerated |
+ # '.1', '.2', etc. tuple param names (if any) |
+ return eval( |
+ 'lambda %s: dict(i for i in locals().items() if not is_tuplename(i[0]))' |
+ % signature, {'is_tuplename':self.is_tuplename}) |
+ |
+ def test_plain(self): |
+ f = self.makeCallable('a, b=1') |
+ self.assertEqualCallArgs(f, '2') |
+ self.assertEqualCallArgs(f, '2, 3') |
+ self.assertEqualCallArgs(f, 'a=2') |
+ self.assertEqualCallArgs(f, 'b=3, a=2') |
+ self.assertEqualCallArgs(f, '2, b=3') |
+ # expand *iterable / **mapping |
+ self.assertEqualCallArgs(f, '*(2,)') |
+ self.assertEqualCallArgs(f, '*[2]') |
+ self.assertEqualCallArgs(f, '*(2, 3)') |
+ self.assertEqualCallArgs(f, '*[2, 3]') |
+ self.assertEqualCallArgs(f, '**{"a":2}') |
+ self.assertEqualCallArgs(f, 'b=3, **{"a":2}') |
+ self.assertEqualCallArgs(f, '2, **{"b":3}') |
+ self.assertEqualCallArgs(f, '**{"b":3, "a":2}') |
+ # expand UserList / UserDict |
+ self.assertEqualCallArgs(f, '*UserList([2])') |
+ self.assertEqualCallArgs(f, '*UserList([2, 3])') |
+ self.assertEqualCallArgs(f, '**UserDict(a=2)') |
+ self.assertEqualCallArgs(f, '2, **UserDict(b=3)') |
+ self.assertEqualCallArgs(f, 'b=2, **UserDict(a=3)') |
+ # unicode keyword args |
+ self.assertEqualCallArgs(f, '**{u"a":2}') |
+ self.assertEqualCallArgs(f, 'b=3, **{u"a":2}') |
+ self.assertEqualCallArgs(f, '2, **{u"b":3}') |
+ self.assertEqualCallArgs(f, '**{u"b":3, u"a":2}') |
+ |
+ def test_varargs(self): |
+ f = self.makeCallable('a, b=1, *c') |
+ self.assertEqualCallArgs(f, '2') |
+ self.assertEqualCallArgs(f, '2, 3') |
+ self.assertEqualCallArgs(f, '2, 3, 4') |
+ self.assertEqualCallArgs(f, '*(2,3,4)') |
+ self.assertEqualCallArgs(f, '2, *[3,4]') |
+ self.assertEqualCallArgs(f, '2, 3, *UserList([4])') |
+ |
+ def test_varkw(self): |
+ f = self.makeCallable('a, b=1, **c') |
+ self.assertEqualCallArgs(f, 'a=2') |
+ self.assertEqualCallArgs(f, '2, b=3, c=4') |
+ self.assertEqualCallArgs(f, 'b=3, a=2, c=4') |
+ self.assertEqualCallArgs(f, 'c=4, **{"a":2, "b":3}') |
+ self.assertEqualCallArgs(f, '2, c=4, **{"b":3}') |
+ self.assertEqualCallArgs(f, 'b=2, **{"a":3, "c":4}') |
+ self.assertEqualCallArgs(f, '**UserDict(a=2, b=3, c=4)') |
+ self.assertEqualCallArgs(f, '2, c=4, **UserDict(b=3)') |
+ self.assertEqualCallArgs(f, 'b=2, **UserDict(a=3, c=4)') |
+ # unicode keyword args |
+ self.assertEqualCallArgs(f, 'c=4, **{u"a":2, u"b":3}') |
+ self.assertEqualCallArgs(f, '2, c=4, **{u"b":3}') |
+ self.assertEqualCallArgs(f, 'b=2, **{u"a":3, u"c":4}') |
+ |
+ def test_tupleargs(self): |
+ f = self.makeCallable('(b,c), (d,(e,f))=(0,[1,2])') |
+ self.assertEqualCallArgs(f, '(2,3)') |
+ self.assertEqualCallArgs(f, '[2,3]') |
+ self.assertEqualCallArgs(f, 'UserList([2,3])') |
+ self.assertEqualCallArgs(f, '(2,3), (4,(5,6))') |
+ self.assertEqualCallArgs(f, '(2,3), (4,[5,6])') |
+ self.assertEqualCallArgs(f, '(2,3), [4,UserList([5,6])]') |
+ |
+ def test_multiple_features(self): |
+ f = self.makeCallable('a, b=2, (c,(d,e))=(3,[4,5]), *f, **g') |
+ self.assertEqualCallArgs(f, '2, 3, (4,[5,6]), 7') |
+ self.assertEqualCallArgs(f, '2, 3, *[(4,[5,6]), 7], x=8') |
+ self.assertEqualCallArgs(f, '2, 3, x=8, *[(4,[5,6]), 7]') |
+ self.assertEqualCallArgs(f, '2, x=8, *[3, (4,[5,6]), 7], y=9') |
+ self.assertEqualCallArgs(f, 'x=8, *[2, 3, (4,[5,6])], y=9') |
+ self.assertEqualCallArgs(f, 'x=8, *UserList([2, 3, (4,[5,6])]), **{"y":9, "z":10}') |
+ self.assertEqualCallArgs(f, '2, x=8, *UserList([3, (4,[5,6])]), **UserDict(y=9, z=10)') |
+ |
+ def test_errors(self): |
+ f0 = self.makeCallable('') |
+ f1 = self.makeCallable('a, b') |
+ f2 = self.makeCallable('a, b=1') |
+ # f0 takes no arguments |
+ self.assertEqualException(f0, '1') |
+ self.assertEqualException(f0, 'x=1') |
+ self.assertEqualException(f0, '1,x=1') |
+ # f1 takes exactly 2 arguments |
+ self.assertEqualException(f1, '') |
+ self.assertEqualException(f1, '1') |
+ self.assertEqualException(f1, 'a=2') |
+ self.assertEqualException(f1, 'b=3') |
+ # f2 takes at least 1 argument |
+ self.assertEqualException(f2, '') |
+ self.assertEqualException(f2, 'b=3') |
+ for f in f1, f2: |
+ # f1/f2 takes exactly/at most 2 arguments |
+ self.assertEqualException(f, '2, 3, 4') |
+ self.assertEqualException(f, '1, 2, 3, a=1') |
+ self.assertEqualException(f, '2, 3, 4, c=5') |
+ self.assertEqualException(f, '2, 3, 4, a=1, c=5') |
+ # f got an unexpected keyword argument |
+ self.assertEqualException(f, 'c=2') |
+ self.assertEqualException(f, '2, c=3') |
+ self.assertEqualException(f, '2, 3, c=4') |
+ self.assertEqualException(f, '2, c=4, b=3') |
+ self.assertEqualException(f, '**{u"\u03c0\u03b9": 4}') |
+ # f got multiple values for keyword argument |
+ self.assertEqualException(f, '1, a=2') |
+ self.assertEqualException(f, '1, **{"a":2}') |
+ self.assertEqualException(f, '1, 2, b=3') |
+ # XXX: Python inconsistency |
+ # - for functions and bound methods: unexpected keyword 'c' |
+ # - for unbound methods: multiple values for keyword 'a' |
+ #self.assertEqualException(f, '1, c=3, a=2') |
+ f = self.makeCallable('(a,b)=(0,1)') |
+ self.assertEqualException(f, '1') |
+ self.assertEqualException(f, '[1]') |
+ self.assertEqualException(f, '(1,2,3)') |
+ |
+class TestGetcallargsMethods(TestGetcallargsFunctions): |
+ |
+ def setUp(self): |
+ class Foo(object): |
+ pass |
+ self.cls = Foo |
+ self.inst = Foo() |
+ |
+ def makeCallable(self, signature): |
+ assert 'self' not in signature |
+ self.cls.method = super(TestGetcallargsMethods, self).makeCallable('self, '+signature) |
+ return self.inst.method |
+ |
+class TestGetcallargsUnboundMethods(TestGetcallargsMethods): |
+ |
+ def makeCallable(self, signature): |
+ super(TestGetcallargsUnboundMethods, self).makeCallable(signature) |
+ return self.cls.method |
+ |
+ def assertEqualCallArgs(self, func, call_params_string, locals=None): |
+ return super(TestGetcallargsUnboundMethods, self).assertEqualCallArgs( |
+ *self._getAssertEqualParams(func, call_params_string, locals)) |
+ |
+ def assertEqualException(self, func, call_params_string, locals=None): |
+ return super(TestGetcallargsUnboundMethods, self).assertEqualException( |
+ *self._getAssertEqualParams(func, call_params_string, locals)) |
+ |
+ def _getAssertEqualParams(self, func, call_params_string, locals=None): |
+ assert 'inst' not in call_params_string |
+ locals = dict(locals or {}, inst=self.inst) |
+ return (func, 'inst,' + call_params_string, locals) |
+ |
+ def test_self_param(self): |
+ # test that it fails if 'self' is not an instance of the class |
+ superAssertEqualException = super(TestGetcallargsUnboundMethods, self).assertEqualException |
+ f = self.makeCallable('a, b') |
+ superAssertEqualException(f, '') |
+ superAssertEqualException(f, '1') |
+ superAssertEqualException(f, 'self=s', {'s':self.inst}) |
+ superAssertEqualException(f, '1, self=s', {'s':self.inst}) |
+ |
def test_main(): |
- run_unittest(TestDecorators, TestRetrievingSourceCode, TestOneliners, |
- TestBuggyCases, |
- TestInterpreterStack, TestClassesAndFunctions, TestPredicates) |
+ run_unittest( |
+ TestDecorators, TestRetrievingSourceCode, TestOneliners, TestBuggyCases, |
+ TestInterpreterStack, TestClassesAndFunctions, TestPredicates, |
+ TestGetcallargsFunctions, TestGetcallargsMethods, TestGetcallargsUnboundMethods) |
if __name__ == "__main__": |
test_main() |