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 an iterable, 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 an iterable, 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 Check for issue #4806: Does a TypeError in a generator get propagated with the
    132 right error message?
    133 
    134     >>> def broken(): raise TypeError("myerror")
    135     ...
    136 
    137     >>> g(*(broken() for i in range(1)))
    138     Traceback (most recent call last):
    139       ...
    140     TypeError: myerror
    141 
    142 Make sure that the function doesn't stomp the dictionary
    143 
    144     >>> d = {'a': 1, 'b': 2, 'c': 3}
    145     >>> d2 = d.copy()
    146     >>> g(1, d=4, **d)
    147     1 () {'a': 1, 'b': 2, 'c': 3, 'd': 4}
    148     >>> d == d2
    149     True
    150 
    151 What about willful misconduct?
    152 
    153     >>> def saboteur(**kw):
    154     ...     kw['x'] = 'm'
    155     ...     return kw
    156 
    157     >>> d = {}
    158     >>> kw = saboteur(a=1, **d)
    159     >>> d
    160     {}
    161 
    162 
    163     >>> g(1, 2, 3, **{'x': 4, 'y': 5})
    164     Traceback (most recent call last):
    165       ...
    166     TypeError: g() got multiple values for keyword argument 'x'
    167 
    168     >>> f(**{1:2})
    169     Traceback (most recent call last):
    170       ...
    171     TypeError: f() keywords must be strings
    172 
    173     >>> h(**{'e': 2})
    174     Traceback (most recent call last):
    175       ...
    176     TypeError: h() got an unexpected keyword argument 'e'
    177 
    178     >>> h(*h)
    179     Traceback (most recent call last):
    180       ...
    181     TypeError: h() argument after * must be an iterable, not function
    182 
    183     >>> h(1, *h)
    184     Traceback (most recent call last):
    185       ...
    186     TypeError: h() argument after * must be an iterable, not function
    187 
    188     >>> dir(*h)
    189     Traceback (most recent call last):
    190       ...
    191     TypeError: dir() argument after * must be an iterable, not function
    192 
    193     >>> None(*h)
    194     Traceback (most recent call last):
    195       ...
    196     TypeError: NoneType object argument after * must be an iterable, \
    197 not function
    198 
    199     >>> h(**h)
    200     Traceback (most recent call last):
    201       ...
    202     TypeError: h() argument after ** must be a mapping, not function
    203 
    204     >>> h(**[])
    205     Traceback (most recent call last):
    206       ...
    207     TypeError: h() argument after ** must be a mapping, not list
    208 
    209     >>> h(a=1, **h)
    210     Traceback (most recent call last):
    211       ...
    212     TypeError: h() argument after ** must be a mapping, not function
    213 
    214     >>> h(a=1, **[])
    215     Traceback (most recent call last):
    216       ...
    217     TypeError: h() argument after ** must be a mapping, not list
    218 
    219     >>> dir(**h)
    220     Traceback (most recent call last):
    221       ...
    222     TypeError: dir() argument after ** must be a mapping, not function
    223 
    224     >>> None(**h)
    225     Traceback (most recent call last):
    226       ...
    227     TypeError: NoneType object argument after ** must be a mapping, \
    228 not function
    229 
    230     >>> dir(b=1, **{'b': 1})
    231     Traceback (most recent call last):
    232       ...
    233     TypeError: dir() got multiple values for keyword argument 'b'
    234 
    235 Another helper function
    236 
    237     >>> def f2(*a, **b):
    238     ...     return a, b
    239 
    240 
    241     >>> d = {}
    242     >>> for i in xrange(512):
    243     ...     key = 'k%d' % i
    244     ...     d[key] = i
    245     >>> a, b = f2(1, *(2,3), **d)
    246     >>> len(a), len(b), b == d
    247     (3, 512, True)
    248 
    249     >>> class Foo:
    250     ...     def method(self, arg1, arg2):
    251     ...         return arg1+arg2
    252 
    253     >>> x = Foo()
    254     >>> Foo.method(*(x, 1, 2))
    255     3
    256     >>> Foo.method(x, *(1, 2))
    257     3
    258     >>> Foo.method(*(1, 2, 3))
    259     Traceback (most recent call last):
    260       ...
    261     TypeError: unbound method method() must be called with Foo instance as \
    262 first argument (got int instance instead)
    263 
    264     >>> Foo.method(1, *[2, 3])
    265     Traceback (most recent call last):
    266       ...
    267     TypeError: unbound method method() must be called with Foo instance as \
    268 first argument (got int instance instead)
    269 
    270 A PyCFunction that takes only positional parameters should allow an
    271 empty keyword dictionary to pass without a complaint, but raise a
    272 TypeError if te dictionary is not empty
    273 
    274     >>> try:
    275     ...     silence = id(1, *{})
    276     ...     True
    277     ... except:
    278     ...     False
    279     True
    280 
    281     >>> id(1, **{'foo': 1})
    282     Traceback (most recent call last):
    283       ...
    284     TypeError: id() takes no keyword arguments
    285 
    286 A corner case of keyword dictionary items being deleted during
    287 the function call setup. See <http://bugs.python.org/issue2016>.
    288 
    289     >>> class Name(str):
    290     ...     def __eq__(self, other):
    291     ...         try:
    292     ...              del x[self]
    293     ...         except KeyError:
    294     ...              pass
    295     ...         return str.__eq__(self, other)
    296     ...     def __hash__(self):
    297     ...         return str.__hash__(self)
    298 
    299     >>> x = {Name("a"):1, Name("b"):2}
    300     >>> def f(a, b):
    301     ...     print a,b
    302     >>> f(**x)
    303     1 2
    304 
    305 An obscure message:
    306 
    307     >>> def f(a, b):
    308     ...    pass
    309     >>> f(b=1)
    310     Traceback (most recent call last):
    311       ...
    312     TypeError: f() takes exactly 2 arguments (1 given)
    313 
    314 The number of arguments passed in includes keywords:
    315 
    316     >>> def f(a):
    317     ...    pass
    318     >>> f(6, a=4, *(1, 2, 3))
    319     Traceback (most recent call last):
    320       ...
    321     TypeError: f() takes exactly 1 argument (5 given)
    322 """
    323 
    324 import unittest
    325 import sys
    326 from test import test_support
    327 
    328 
    329 class ExtCallTest(unittest.TestCase):
    330 
    331     def test_unicode_keywords(self):
    332         def f(a):
    333             return a
    334         self.assertEqual(f(**{u'a': 4}), 4)
    335         self.assertRaises(TypeError, f, **{u'stren': 4})
    336         self.assertRaises(TypeError, f, **{u'someLongString':2})
    337         try:
    338             f(a=4, **{u'a': 4})
    339         except TypeError:
    340             pass
    341         else:
    342             self.fail("duplicate arguments didn't raise")
    343 
    344 
    345 def test_main():
    346     test_support.run_doctest(sys.modules[__name__], True)
    347     test_support.run_unittest(ExtCallTest)
    348 
    349 if __name__ == '__main__':
    350     test_main()
    351