Home | History | Annotate | Download | only in test
      1 # -*- coding: utf-8 -*-

      2 
      3 """Doctest for method/function calls.
      4 
      5 We're going the use these types for extra testing
      6 
      7     >>> from UserList import UserList
      8     >>> from UserDict import UserDict
      9 
     10 We're defining four helper functions
     11 
     12     >>> def e(a,b):
     13     ...     print a, b
     14 
     15     >>> def f(*a, **k):
     16     ...     print a, test_support.sortdict(k)
     17 
     18     >>> def g(x, *y, **z):
     19     ...     print x, y, test_support.sortdict(z)
     20 
     21     >>> def h(j=1, a=2, h=3):
     22     ...     print j, a, h
     23 
     24 Argument list examples
     25 
     26     >>> f()
     27     () {}
     28     >>> f(1)
     29     (1,) {}
     30     >>> f(1, 2)
     31     (1, 2) {}
     32     >>> f(1, 2, 3)
     33     (1, 2, 3) {}
     34     >>> f(1, 2, 3, *(4, 5))
     35     (1, 2, 3, 4, 5) {}
     36     >>> f(1, 2, 3, *[4, 5])
     37     (1, 2, 3, 4, 5) {}
     38     >>> f(1, 2, 3, *UserList([4, 5]))
     39     (1, 2, 3, 4, 5) {}
     40 
     41 Here we add keyword arguments
     42 
     43     >>> f(1, 2, 3, **{'a':4, 'b':5})
     44     (1, 2, 3) {'a': 4, 'b': 5}
     45     >>> f(1, 2, 3, *[4, 5], **{'a':6, 'b':7})
     46     (1, 2, 3, 4, 5) {'a': 6, 'b': 7}
     47     >>> f(1, 2, 3, x=4, y=5, *(6, 7), **{'a':8, 'b': 9})
     48     (1, 2, 3, 6, 7) {'a': 8, 'b': 9, 'x': 4, 'y': 5}
     49 
     50     >>> f(1, 2, 3, **UserDict(a=4, b=5))
     51     (1, 2, 3) {'a': 4, 'b': 5}
     52     >>> f(1, 2, 3, *(4, 5), **UserDict(a=6, b=7))
     53     (1, 2, 3, 4, 5) {'a': 6, 'b': 7}
     54     >>> f(1, 2, 3, x=4, y=5, *(6, 7), **UserDict(a=8, b=9))
     55     (1, 2, 3, 6, 7) {'a': 8, 'b': 9, 'x': 4, 'y': 5}
     56 
     57 Examples with invalid arguments (TypeErrors). We're also testing the function
     58 names in the exception messages.
     59 
     60 Verify clearing of SF bug #733667
     61 
     62     >>> e(c=4)
     63     Traceback (most recent call last):
     64       ...
     65     TypeError: e() got an unexpected keyword argument 'c'
     66 
     67     >>> g()
     68     Traceback (most recent call last):
     69       ...
     70     TypeError: g() takes at least 1 argument (0 given)
     71 
     72     >>> g(*())
     73     Traceback (most recent call last):
     74       ...
     75     TypeError: g() takes at least 1 argument (0 given)
     76 
     77     >>> g(*(), **{})
     78     Traceback (most recent call last):
     79       ...
     80     TypeError: g() takes at least 1 argument (0 given)
     81 
     82     >>> g(1)
     83     1 () {}
     84     >>> g(1, 2)
     85     1 (2,) {}
     86     >>> g(1, 2, 3)
     87     1 (2, 3) {}
     88     >>> g(1, 2, 3, *(4, 5))
     89     1 (2, 3, 4, 5) {}
     90 
     91     >>> class Nothing: pass
     92     ...
     93     >>> g(*Nothing())
     94     Traceback (most recent call last):
     95       ...
     96     TypeError: g() argument after * must be a sequence, not instance
     97 
     98     >>> class Nothing:
     99     ...     def __len__(self): return 5
    100     ...
    101 
    102     >>> g(*Nothing())
    103     Traceback (most recent call last):
    104       ...
    105     TypeError: g() argument after * must be a sequence, not instance
    106 
    107     >>> class Nothing():
    108     ...     def __len__(self): return 5
    109     ...     def __getitem__(self, i):
    110     ...         if i<3: return i
    111     ...         else: raise IndexError(i)
    112     ...
    113 
    114     >>> g(*Nothing())
    115     0 (1, 2) {}
    116 
    117     >>> class Nothing:
    118     ...     def __init__(self): self.c = 0
    119     ...     def __iter__(self): return self
    120     ...     def next(self):
    121     ...         if self.c == 4:
    122     ...             raise StopIteration
    123     ...         c = self.c
    124     ...         self.c += 1
    125     ...         return c
    126     ...
    127 
    128     >>> g(*Nothing())
    129     0 (1, 2, 3) {}
    130 
    131 Make sure that the function doesn't stomp the dictionary
    132 
    133     >>> d = {'a': 1, 'b': 2, 'c': 3}
    134     >>> d2 = d.copy()
    135     >>> g(1, d=4, **d)
    136     1 () {'a': 1, 'b': 2, 'c': 3, 'd': 4}
    137     >>> d == d2
    138     True
    139 
    140 What about willful misconduct?
    141 
    142     >>> def saboteur(**kw):
    143     ...     kw['x'] = 'm'
    144     ...     return kw
    145 
    146     >>> d = {}
    147     >>> kw = saboteur(a=1, **d)
    148     >>> d
    149     {}
    150 
    151 
    152     >>> g(1, 2, 3, **{'x': 4, 'y': 5})
    153     Traceback (most recent call last):
    154       ...
    155     TypeError: g() got multiple values for keyword argument 'x'
    156 
    157     >>> f(**{1:2})
    158     Traceback (most recent call last):
    159       ...
    160     TypeError: f() keywords must be strings
    161 
    162     >>> h(**{'e': 2})
    163     Traceback (most recent call last):
    164       ...
    165     TypeError: h() got an unexpected keyword argument 'e'
    166 
    167     >>> h(*h)
    168     Traceback (most recent call last):
    169       ...
    170     TypeError: h() argument after * must be a sequence, not function
    171 
    172     >>> dir(*h)
    173     Traceback (most recent call last):
    174       ...
    175     TypeError: dir() argument after * must be a sequence, not function
    176 
    177     >>> None(*h)
    178     Traceback (most recent call last):
    179       ...
    180     TypeError: NoneType object argument after * must be a sequence, \
    181 not function
    182 
    183     >>> h(**h)
    184     Traceback (most recent call last):
    185       ...
    186     TypeError: h() argument after ** must be a mapping, not function
    187 
    188     >>> dir(**h)
    189     Traceback (most recent call last):
    190       ...
    191     TypeError: dir() argument after ** must be a mapping, not function
    192 
    193     >>> None(**h)
    194     Traceback (most recent call last):
    195       ...
    196     TypeError: NoneType object argument after ** must be a mapping, \
    197 not function
    198 
    199     >>> dir(b=1, **{'b': 1})
    200     Traceback (most recent call last):
    201       ...
    202     TypeError: dir() got multiple values for keyword argument 'b'
    203 
    204 Another helper function
    205 
    206     >>> def f2(*a, **b):
    207     ...     return a, b
    208 
    209 
    210     >>> d = {}
    211     >>> for i in xrange(512):
    212     ...     key = 'k%d' % i
    213     ...     d[key] = i
    214     >>> a, b = f2(1, *(2,3), **d)
    215     >>> len(a), len(b), b == d
    216     (3, 512, True)
    217 
    218     >>> class Foo:
    219     ...     def method(self, arg1, arg2):
    220     ...         return arg1+arg2
    221 
    222     >>> x = Foo()
    223     >>> Foo.method(*(x, 1, 2))
    224     3
    225     >>> Foo.method(x, *(1, 2))
    226     3
    227     >>> Foo.method(*(1, 2, 3))
    228     Traceback (most recent call last):
    229       ...
    230     TypeError: unbound method method() must be called with Foo instance as \
    231 first argument (got int instance instead)
    232 
    233     >>> Foo.method(1, *[2, 3])
    234     Traceback (most recent call last):
    235       ...
    236     TypeError: unbound method method() must be called with Foo instance as \
    237 first argument (got int instance instead)
    238 
    239 A PyCFunction that takes only positional parameters should allow an
    240 empty keyword dictionary to pass without a complaint, but raise a
    241 TypeError if te dictionary is not empty
    242 
    243     >>> try:
    244     ...     silence = id(1, *{})
    245     ...     True
    246     ... except:
    247     ...     False
    248     True
    249 
    250     >>> id(1, **{'foo': 1})
    251     Traceback (most recent call last):
    252       ...
    253     TypeError: id() takes no keyword arguments
    254 
    255 A corner case of keyword dictionary items being deleted during
    256 the function call setup. See <http://bugs.python.org/issue2016>.
    257 
    258     >>> class Name(str):
    259     ...     def __eq__(self, other):
    260     ...         try:
    261     ...              del x[self]
    262     ...         except KeyError:
    263     ...              pass
    264     ...         return str.__eq__(self, other)
    265     ...     def __hash__(self):
    266     ...         return str.__hash__(self)
    267 
    268     >>> x = {Name("a"):1, Name("b"):2}
    269     >>> def f(a, b):
    270     ...     print a,b
    271     >>> f(**x)
    272     1 2
    273 
    274 A obscure message:
    275 
    276     >>> def f(a, b):
    277     ...    pass
    278     >>> f(b=1)
    279     Traceback (most recent call last):
    280       ...
    281     TypeError: f() takes exactly 2 arguments (1 given)
    282 
    283 The number of arguments passed in includes keywords:
    284 
    285     >>> def f(a):
    286     ...    pass
    287     >>> f(6, a=4, *(1, 2, 3))
    288     Traceback (most recent call last):
    289       ...
    290     TypeError: f() takes exactly 1 argument (5 given)
    291 """
    292 
    293 import unittest
    294 import sys
    295 from test import test_support
    296 
    297 
    298 class ExtCallTest(unittest.TestCase):
    299 
    300     def test_unicode_keywords(self):
    301         def f(a):
    302             return a
    303         self.assertEqual(f(**{u'a': 4}), 4)
    304         self.assertRaises(TypeError, f, **{u'stren': 4})
    305         self.assertRaises(TypeError, f, **{u'someLongString':2})
    306         try:
    307             f(a=4, **{u'a': 4})
    308         except TypeError:
    309             pass
    310         else:
    311             self.fail("duplicate arguments didn't raise")
    312 
    313 
    314 def test_main():
    315     test_support.run_doctest(sys.modules[__name__], True)
    316     test_support.run_unittest(ExtCallTest)
    317 
    318 if __name__ == '__main__':
    319     test_main()
    320