python (3.11.7)

(root)/
lib/
python3.11/
test/
test_extcall.py
       1  
       2  """Doctest for method/function calls.
       3  
       4  We're going the use these types for extra testing
       5  
       6      >>> from collections import UserList
       7      >>> from collections import UserDict
       8  
       9  We're defining four helper functions
      10  
      11      >>> def e(a,b):
      12      ...     print(a, b)
      13  
      14      >>> def f(*a, **k):
      15      ...     print(a, support.sortdict(k))
      16  
      17      >>> def g(x, *y, **z):
      18      ...     print(x, y, support.sortdict(z))
      19  
      20      >>> def h(j=1, a=2, h=3):
      21      ...     print(j, a, h)
      22  
      23  Argument list examples
      24  
      25      >>> f()
      26      () {}
      27      >>> f(1)
      28      (1,) {}
      29      >>> f(1, 2)
      30      (1, 2) {}
      31      >>> f(1, 2, 3)
      32      (1, 2, 3) {}
      33      >>> f(1, 2, 3, *(4, 5))
      34      (1, 2, 3, 4, 5) {}
      35      >>> f(1, 2, 3, *[4, 5])
      36      (1, 2, 3, 4, 5) {}
      37      >>> f(*[1, 2, 3], 4, 5)
      38      (1, 2, 3, 4, 5) {}
      39      >>> f(1, 2, 3, *UserList([4, 5]))
      40      (1, 2, 3, 4, 5) {}
      41      >>> f(1, 2, 3, *[4, 5], *[6, 7])
      42      (1, 2, 3, 4, 5, 6, 7) {}
      43      >>> f(1, *[2, 3], 4, *[5, 6], 7)
      44      (1, 2, 3, 4, 5, 6, 7) {}
      45      >>> f(*UserList([1, 2]), *UserList([3, 4]), 5, *UserList([6, 7]))
      46      (1, 2, 3, 4, 5, 6, 7) {}
      47  
      48  Here we add keyword arguments
      49  
      50      >>> f(1, 2, 3, **{'a':4, 'b':5})
      51      (1, 2, 3) {'a': 4, 'b': 5}
      52      >>> f(1, 2, **{'a': -1, 'b': 5}, **{'a': 4, 'c': 6})
      53      Traceback (most recent call last):
      54          ...
      55      TypeError: test.test_extcall.f() got multiple values for keyword argument 'a'
      56      >>> f(1, 2, **{'a': -1, 'b': 5}, a=4, c=6)
      57      Traceback (most recent call last):
      58          ...
      59      TypeError: test.test_extcall.f() got multiple values for keyword argument 'a'
      60      >>> f(1, 2, a=3, **{'a': 4}, **{'a': 5})
      61      Traceback (most recent call last):
      62          ...
      63      TypeError: test.test_extcall.f() got multiple values for keyword argument 'a'
      64      >>> f(1, 2, 3, *[4, 5], **{'a':6, 'b':7})
      65      (1, 2, 3, 4, 5) {'a': 6, 'b': 7}
      66      >>> f(1, 2, 3, x=4, y=5, *(6, 7), **{'a':8, 'b': 9})
      67      (1, 2, 3, 6, 7) {'a': 8, 'b': 9, 'x': 4, 'y': 5}
      68      >>> f(1, 2, 3, *[4, 5], **{'c': 8}, **{'a':6, 'b':7})
      69      (1, 2, 3, 4, 5) {'a': 6, 'b': 7, 'c': 8}
      70      >>> f(1, 2, 3, *(4, 5), x=6, y=7, **{'a':8, 'b': 9})
      71      (1, 2, 3, 4, 5) {'a': 8, 'b': 9, 'x': 6, 'y': 7}
      72  
      73      >>> f(1, 2, 3, **UserDict(a=4, b=5))
      74      (1, 2, 3) {'a': 4, 'b': 5}
      75      >>> f(1, 2, 3, *(4, 5), **UserDict(a=6, b=7))
      76      (1, 2, 3, 4, 5) {'a': 6, 'b': 7}
      77      >>> f(1, 2, 3, x=4, y=5, *(6, 7), **UserDict(a=8, b=9))
      78      (1, 2, 3, 6, 7) {'a': 8, 'b': 9, 'x': 4, 'y': 5}
      79      >>> f(1, 2, 3, *(4, 5), x=6, y=7, **UserDict(a=8, b=9))
      80      (1, 2, 3, 4, 5) {'a': 8, 'b': 9, 'x': 6, 'y': 7}
      81  
      82  Mix keyword arguments and dict unpacking
      83  
      84      >>> d1 = {'a':1}
      85  
      86      >>> d2 = {'c':3}
      87  
      88      >>> f(b=2, **d1, **d2)
      89      () {'a': 1, 'b': 2, 'c': 3}
      90  
      91      >>> f(**d1, b=2, **d2)
      92      () {'a': 1, 'b': 2, 'c': 3}
      93  
      94      >>> f(**d1, **d2, b=2)
      95      () {'a': 1, 'b': 2, 'c': 3}
      96  
      97      >>> f(**d1, b=2, **d2, d=4)
      98      () {'a': 1, 'b': 2, 'c': 3, 'd': 4}
      99  
     100  Examples with invalid arguments (TypeErrors). We're also testing the function
     101  names in the exception messages.
     102  
     103  Verify clearing of SF bug #733667
     104  
     105      >>> e(c=4)
     106      Traceback (most recent call last):
     107        ...
     108      TypeError: e() got an unexpected keyword argument 'c'
     109  
     110      >>> g()
     111      Traceback (most recent call last):
     112        ...
     113      TypeError: g() missing 1 required positional argument: 'x'
     114  
     115      >>> g(*())
     116      Traceback (most recent call last):
     117        ...
     118      TypeError: g() missing 1 required positional argument: 'x'
     119  
     120      >>> g(*(), **{})
     121      Traceback (most recent call last):
     122        ...
     123      TypeError: g() missing 1 required positional argument: 'x'
     124  
     125      >>> g(1)
     126      1 () {}
     127      >>> g(1, 2)
     128      1 (2,) {}
     129      >>> g(1, 2, 3)
     130      1 (2, 3) {}
     131      >>> g(1, 2, 3, *(4, 5))
     132      1 (2, 3, 4, 5) {}
     133  
     134      >>> class Nothing: pass
     135      ...
     136      >>> g(*Nothing())
     137      Traceback (most recent call last):
     138        ...
     139      TypeError: test.test_extcall.g() argument after * must be an iterable, not Nothing
     140  
     141      >>> class Nothing:
     142      ...     def __len__(self): return 5
     143      ...
     144  
     145      >>> g(*Nothing())
     146      Traceback (most recent call last):
     147        ...
     148      TypeError: test.test_extcall.g() argument after * must be an iterable, not Nothing
     149  
     150      >>> class Nothing():
     151      ...     def __len__(self): return 5
     152      ...     def __getitem__(self, i):
     153      ...         if i<3: return i
     154      ...         else: raise IndexError(i)
     155      ...
     156  
     157      >>> g(*Nothing())
     158      0 (1, 2) {}
     159  
     160      >>> class Nothing:
     161      ...     def __init__(self): self.c = 0
     162      ...     def __iter__(self): return self
     163      ...     def __next__(self):
     164      ...         if self.c == 4:
     165      ...             raise StopIteration
     166      ...         c = self.c
     167      ...         self.c += 1
     168      ...         return c
     169      ...
     170  
     171      >>> g(*Nothing())
     172      0 (1, 2, 3) {}
     173  
     174  Check for issue #4806: Does a TypeError in a generator get propagated with the
     175  right error message? (Also check with other iterables.)
     176  
     177      >>> def broken(): raise TypeError("myerror")
     178      ...
     179  
     180      >>> g(*(broken() for i in range(1)))
     181      Traceback (most recent call last):
     182        ...
     183      TypeError: myerror
     184      >>> g(*range(1), *(broken() for i in range(1)))
     185      Traceback (most recent call last):
     186        ...
     187      TypeError: myerror
     188  
     189      >>> class BrokenIterable1:
     190      ...     def __iter__(self):
     191      ...         raise TypeError('myerror')
     192      ...
     193      >>> g(*BrokenIterable1())
     194      Traceback (most recent call last):
     195        ...
     196      TypeError: myerror
     197      >>> g(*range(1), *BrokenIterable1())
     198      Traceback (most recent call last):
     199        ...
     200      TypeError: myerror
     201  
     202      >>> class BrokenIterable2:
     203      ...     def __iter__(self):
     204      ...         yield 0
     205      ...         raise TypeError('myerror')
     206      ...
     207      >>> g(*BrokenIterable2())
     208      Traceback (most recent call last):
     209        ...
     210      TypeError: myerror
     211      >>> g(*range(1), *BrokenIterable2())
     212      Traceback (most recent call last):
     213        ...
     214      TypeError: myerror
     215  
     216      >>> class BrokenSequence:
     217      ...     def __getitem__(self, idx):
     218      ...         raise TypeError('myerror')
     219      ...
     220      >>> g(*BrokenSequence())
     221      Traceback (most recent call last):
     222        ...
     223      TypeError: myerror
     224      >>> g(*range(1), *BrokenSequence())
     225      Traceback (most recent call last):
     226        ...
     227      TypeError: myerror
     228  
     229  Make sure that the function doesn't stomp the dictionary
     230  
     231      >>> d = {'a': 1, 'b': 2, 'c': 3}
     232      >>> d2 = d.copy()
     233      >>> g(1, d=4, **d)
     234      1 () {'a': 1, 'b': 2, 'c': 3, 'd': 4}
     235      >>> d == d2
     236      True
     237  
     238  What about willful misconduct?
     239  
     240      >>> def saboteur(**kw):
     241      ...     kw['x'] = 'm'
     242      ...     return kw
     243  
     244      >>> d = {}
     245      >>> kw = saboteur(a=1, **d)
     246      >>> d
     247      {}
     248  
     249  
     250      >>> g(1, 2, 3, **{'x': 4, 'y': 5})
     251      Traceback (most recent call last):
     252        ...
     253      TypeError: g() got multiple values for argument 'x'
     254  
     255      >>> f(**{1:2})
     256      Traceback (most recent call last):
     257        ...
     258      TypeError: keywords must be strings
     259  
     260      >>> h(**{'e': 2})
     261      Traceback (most recent call last):
     262        ...
     263      TypeError: h() got an unexpected keyword argument 'e'
     264  
     265      >>> h(*h)
     266      Traceback (most recent call last):
     267        ...
     268      TypeError: test.test_extcall.h() argument after * must be an iterable, not function
     269  
     270      >>> h(1, *h)
     271      Traceback (most recent call last):
     272        ...
     273      TypeError: Value after * must be an iterable, not function
     274  
     275      >>> h(*[1], *h)
     276      Traceback (most recent call last):
     277        ...
     278      TypeError: Value after * must be an iterable, not function
     279  
     280      >>> dir(*h)
     281      Traceback (most recent call last):
     282        ...
     283      TypeError: dir() argument after * must be an iterable, not function
     284  
     285      >>> nothing = None
     286      >>> nothing(*h)
     287      Traceback (most recent call last):
     288        ...
     289      TypeError: None argument after * must be an iterable, \
     290  not function
     291  
     292      >>> h(**h)
     293      Traceback (most recent call last):
     294        ...
     295      TypeError: test.test_extcall.h() argument after ** must be a mapping, not function
     296  
     297      >>> h(**[])
     298      Traceback (most recent call last):
     299        ...
     300      TypeError: test.test_extcall.h() argument after ** must be a mapping, not list
     301  
     302      >>> h(a=1, **h)
     303      Traceback (most recent call last):
     304        ...
     305      TypeError: test.test_extcall.h() argument after ** must be a mapping, not function
     306  
     307      >>> h(a=1, **[])
     308      Traceback (most recent call last):
     309        ...
     310      TypeError: test.test_extcall.h() argument after ** must be a mapping, not list
     311  
     312      >>> h(**{'a': 1}, **h)
     313      Traceback (most recent call last):
     314        ...
     315      TypeError: test.test_extcall.h() argument after ** must be a mapping, not function
     316  
     317      >>> h(**{'a': 1}, **[])
     318      Traceback (most recent call last):
     319        ...
     320      TypeError: test.test_extcall.h() argument after ** must be a mapping, not list
     321  
     322      >>> dir(**h)
     323      Traceback (most recent call last):
     324        ...
     325      TypeError: dir() argument after ** must be a mapping, not function
     326  
     327      >>> nothing(**h)
     328      Traceback (most recent call last):
     329        ...
     330      TypeError: None argument after ** must be a mapping, \
     331  not function
     332  
     333      >>> dir(b=1, **{'b': 1})
     334      Traceback (most recent call last):
     335        ...
     336      TypeError: dir() got multiple values for keyword argument 'b'
     337  
     338  Test a kwargs mapping with duplicated keys.
     339  
     340      >>> from collections.abc import Mapping
     341      >>> class MultiDict(Mapping):
     342      ...     def __init__(self, items):
     343      ...         self._items = items
     344      ...
     345      ...     def __iter__(self):
     346      ...         return (k for k, v in self._items)
     347      ...
     348      ...     def __getitem__(self, key):
     349      ...         for k, v in self._items:
     350      ...             if k == key:
     351      ...                 return v
     352      ...         raise KeyError(key)
     353      ...
     354      ...     def __len__(self):
     355      ...         return len(self._items)
     356      ...
     357      ...     def keys(self):
     358      ...         return [k for k, v in self._items]
     359      ...
     360      ...     def values(self):
     361      ...         return [v for k, v in self._items]
     362      ...
     363      ...     def items(self):
     364      ...         return [(k, v) for k, v in self._items]
     365      ...
     366      >>> g(**MultiDict([('x', 1), ('y', 2)]))
     367      1 () {'y': 2}
     368  
     369      >>> g(**MultiDict([('x', 1), ('x', 2)]))
     370      Traceback (most recent call last):
     371        ...
     372      TypeError: test.test_extcall.g() got multiple values for keyword argument 'x'
     373  
     374      >>> g(a=3, **MultiDict([('x', 1), ('x', 2)]))
     375      Traceback (most recent call last):
     376        ...
     377      TypeError: test.test_extcall.g() got multiple values for keyword argument 'x'
     378  
     379      >>> g(**MultiDict([('a', 3)]), **MultiDict([('x', 1), ('x', 2)]))
     380      Traceback (most recent call last):
     381        ...
     382      TypeError: test.test_extcall.g() got multiple values for keyword argument 'x'
     383  
     384  Another helper function
     385  
     386      >>> def f2(*a, **b):
     387      ...     return a, b
     388  
     389  
     390      >>> d = {}
     391      >>> for i in range(512):
     392      ...     key = 'k%d' % i
     393      ...     d[key] = i
     394      >>> a, b = f2(1, *(2,3), **d)
     395      >>> len(a), len(b), b == d
     396      (3, 512, True)
     397  
     398      >>> class Foo:
     399      ...     def method(self, arg1, arg2):
     400      ...         return arg1+arg2
     401  
     402      >>> x = Foo()
     403      >>> Foo.method(*(x, 1, 2))
     404      3
     405      >>> Foo.method(x, *(1, 2))
     406      3
     407      >>> Foo.method(*(1, 2, 3))
     408      5
     409      >>> Foo.method(1, *[2, 3])
     410      5
     411  
     412  A PyCFunction that takes only positional parameters should allow an
     413  empty keyword dictionary to pass without a complaint, but raise a
     414  TypeError if te dictionary is not empty
     415  
     416      >>> try:
     417      ...     silence = id(1, *{})
     418      ...     True
     419      ... except:
     420      ...     False
     421      True
     422  
     423      >>> id(1, **{'foo': 1})
     424      Traceback (most recent call last):
     425        ...
     426      TypeError: id() takes no keyword arguments
     427  
     428  A corner case of keyword dictionary items being deleted during
     429  the function call setup. See <http://bugs.python.org/issue2016>.
     430  
     431      >>> class Name(str):
     432      ...     def __eq__(self, other):
     433      ...         try:
     434      ...              del x[self]
     435      ...         except KeyError:
     436      ...              pass
     437      ...         return str.__eq__(self, other)
     438      ...     def __hash__(self):
     439      ...         return str.__hash__(self)
     440  
     441      >>> x = {Name("a"):1, Name("b"):2}
     442      >>> def f(a, b):
     443      ...     print(a,b)
     444      >>> f(**x)
     445      1 2
     446  
     447  Too many arguments:
     448  
     449      >>> def f(): pass
     450      >>> f(1)
     451      Traceback (most recent call last):
     452        ...
     453      TypeError: f() takes 0 positional arguments but 1 was given
     454      >>> def f(a): pass
     455      >>> f(1, 2)
     456      Traceback (most recent call last):
     457        ...
     458      TypeError: f() takes 1 positional argument but 2 were given
     459      >>> def f(a, b=1): pass
     460      >>> f(1, 2, 3)
     461      Traceback (most recent call last):
     462        ...
     463      TypeError: f() takes from 1 to 2 positional arguments but 3 were given
     464      >>> def f(*, kw): pass
     465      >>> f(1, kw=3)
     466      Traceback (most recent call last):
     467        ...
     468      TypeError: f() takes 0 positional arguments but 1 positional argument (and 1 keyword-only argument) were given
     469      >>> def f(*, kw, b): pass
     470      >>> f(1, 2, 3, b=3, kw=3)
     471      Traceback (most recent call last):
     472        ...
     473      TypeError: f() takes 0 positional arguments but 3 positional arguments (and 2 keyword-only arguments) were given
     474      >>> def f(a, b=2, *, kw): pass
     475      >>> f(2, 3, 4, kw=4)
     476      Traceback (most recent call last):
     477        ...
     478      TypeError: f() takes from 1 to 2 positional arguments but 3 positional arguments (and 1 keyword-only argument) were given
     479  
     480  Too few and missing arguments:
     481  
     482      >>> def f(a): pass
     483      >>> f()
     484      Traceback (most recent call last):
     485        ...
     486      TypeError: f() missing 1 required positional argument: 'a'
     487      >>> def f(a, b): pass
     488      >>> f()
     489      Traceback (most recent call last):
     490        ...
     491      TypeError: f() missing 2 required positional arguments: 'a' and 'b'
     492      >>> def f(a, b, c): pass
     493      >>> f()
     494      Traceback (most recent call last):
     495        ...
     496      TypeError: f() missing 3 required positional arguments: 'a', 'b', and 'c'
     497      >>> def f(a, b, c, d, e): pass
     498      >>> f()
     499      Traceback (most recent call last):
     500        ...
     501      TypeError: f() missing 5 required positional arguments: 'a', 'b', 'c', 'd', and 'e'
     502      >>> def f(a, b=4, c=5, d=5): pass
     503      >>> f(c=12, b=9)
     504      Traceback (most recent call last):
     505        ...
     506      TypeError: f() missing 1 required positional argument: 'a'
     507  
     508  Same with keyword only args:
     509  
     510      >>> def f(*, w): pass
     511      >>> f()
     512      Traceback (most recent call last):
     513        ...
     514      TypeError: f() missing 1 required keyword-only argument: 'w'
     515      >>> def f(*, a, b, c, d, e): pass
     516      >>> f()
     517      Traceback (most recent call last):
     518        ...
     519      TypeError: f() missing 5 required keyword-only arguments: 'a', 'b', 'c', 'd', and 'e'
     520  
     521  """
     522  
     523  import doctest
     524  import unittest
     525  from test import support
     526  
     527  def load_tests(loader, tests, pattern):
     528      tests.addTest(doctest.DocTestSuite())
     529      return tests
     530  
     531  
     532  if __name__ == '__main__':
     533      unittest.main()