test_inspect_args.py 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500
  1. import functools
  2. import inspect
  3. import itertools
  4. import operator
  5. import toolz
  6. from toolz.functoolz import (curry, is_valid_args, is_partial_args, is_arity,
  7. num_required_args, has_varargs, has_keywords)
  8. from toolz._signatures import builtins
  9. import toolz._signatures as _sigs
  10. from toolz.compatibility import PY3, PY33
  11. from toolz.utils import raises
  12. def make_func(param_string, raise_if_called=True):
  13. if not param_string.startswith('('):
  14. param_string = '(%s)' % param_string
  15. if raise_if_called:
  16. body = 'raise ValueError("function should not be called")'
  17. else:
  18. body = 'return True'
  19. d = {}
  20. exec('def func%s:\n %s' % (param_string, body), globals(), d)
  21. return d['func']
  22. def test_make_func():
  23. f = make_func('')
  24. assert raises(ValueError, lambda: f())
  25. assert raises(TypeError, lambda: f(1))
  26. f = make_func('', raise_if_called=False)
  27. assert f()
  28. assert raises(TypeError, lambda: f(1))
  29. f = make_func('x, y=1', raise_if_called=False)
  30. assert f(1)
  31. assert f(x=1)
  32. assert f(1, 2)
  33. assert f(x=1, y=2)
  34. assert raises(TypeError, lambda: f(1, 2, 3))
  35. f = make_func('(x, y=1)', raise_if_called=False)
  36. assert f(1)
  37. assert f(x=1)
  38. assert f(1, 2)
  39. assert f(x=1, y=2)
  40. assert raises(TypeError, lambda: f(1, 2, 3))
  41. def test_is_valid(check_valid=is_valid_args, incomplete=False):
  42. orig_check_valid = check_valid
  43. check_valid = lambda func, *args, **kwargs: orig_check_valid(func, args, kwargs)
  44. f = make_func('')
  45. assert check_valid(f)
  46. assert check_valid(f, 1) is False
  47. assert check_valid(f, x=1) is False
  48. f = make_func('x')
  49. assert check_valid(f) is incomplete
  50. assert check_valid(f, 1)
  51. assert check_valid(f, x=1)
  52. assert check_valid(f, 1, x=2) is False
  53. assert check_valid(f, 1, y=2) is False
  54. assert check_valid(f, 1, 2) is False
  55. assert check_valid(f, x=1, y=2) is False
  56. f = make_func('x=1')
  57. assert check_valid(f)
  58. assert check_valid(f, 1)
  59. assert check_valid(f, x=1)
  60. assert check_valid(f, 1, x=2) is False
  61. assert check_valid(f, 1, y=2) is False
  62. assert check_valid(f, 1, 2) is False
  63. assert check_valid(f, x=1, y=2) is False
  64. f = make_func('*args')
  65. assert check_valid(f)
  66. assert check_valid(f, 1)
  67. assert check_valid(f, 1, 2)
  68. assert check_valid(f, x=1) is False
  69. f = make_func('**kwargs')
  70. assert check_valid(f)
  71. assert check_valid(f, x=1)
  72. assert check_valid(f, x=1, y=2)
  73. assert check_valid(f, 1) is False
  74. f = make_func('x, *args')
  75. assert check_valid(f) is incomplete
  76. assert check_valid(f, 1)
  77. assert check_valid(f, 1, 2)
  78. assert check_valid(f, x=1)
  79. assert check_valid(f, 1, x=1) is False
  80. assert check_valid(f, 1, y=1) is False
  81. f = make_func('x, y=1, **kwargs')
  82. assert check_valid(f) is incomplete
  83. assert check_valid(f, 1)
  84. assert check_valid(f, x=1)
  85. assert check_valid(f, 1, 2)
  86. assert check_valid(f, x=1, y=2, z=3)
  87. assert check_valid(f, 1, 2, y=3) is False
  88. f = make_func('a, b, c=3, d=4')
  89. assert check_valid(f) is incomplete
  90. assert check_valid(f, 1) is incomplete
  91. assert check_valid(f, 1, 2)
  92. assert check_valid(f, 1, c=3) is incomplete
  93. assert check_valid(f, 1, e=3) is False
  94. assert check_valid(f, 1, 2, e=3) is False
  95. assert check_valid(f, 1, 2, b=3) is False
  96. assert check_valid(1) is False
  97. def test_is_valid_py3(check_valid=is_valid_args, incomplete=False):
  98. if not PY3:
  99. return
  100. orig_check_valid = check_valid
  101. check_valid = lambda func, *args, **kwargs: orig_check_valid(func, args, kwargs)
  102. f = make_func('x, *, y=1')
  103. assert check_valid(f) is incomplete
  104. assert check_valid(f, 1)
  105. assert check_valid(f, x=1)
  106. assert check_valid(f, 1, y=2)
  107. assert check_valid(f, 1, 2) is False
  108. assert check_valid(f, 1, z=2) is False
  109. f = make_func('x, *args, y=1')
  110. assert check_valid(f) is incomplete
  111. assert check_valid(f, 1)
  112. assert check_valid(f, x=1)
  113. assert check_valid(f, 1, y=2)
  114. assert check_valid(f, 1, 2, y=2)
  115. assert check_valid(f, 1, 2)
  116. assert check_valid(f, 1, z=2) is False
  117. f = make_func('*, y=1')
  118. assert check_valid(f)
  119. assert check_valid(f, 1) is False
  120. assert check_valid(f, y=1)
  121. assert check_valid(f, z=1) is False
  122. f = make_func('x, *, y')
  123. assert check_valid(f) is incomplete
  124. assert check_valid(f, 1) is incomplete
  125. assert check_valid(f, x=1) is incomplete
  126. assert check_valid(f, 1, y=2)
  127. assert check_valid(f, x=1, y=2)
  128. assert check_valid(f, 1, 2) is False
  129. assert check_valid(f, 1, z=2) is False
  130. assert check_valid(f, 1, y=1, z=2) is False
  131. f = make_func('x=1, *, y, z=3')
  132. assert check_valid(f) is incomplete
  133. assert check_valid(f, 1, z=3) is incomplete
  134. assert check_valid(f, y=2)
  135. assert check_valid(f, 1, y=2)
  136. assert check_valid(f, x=1, y=2)
  137. assert check_valid(f, x=1, y=2, z=3)
  138. assert check_valid(f, 1, x=1, y=2) is False
  139. assert check_valid(f, 1, 3, y=2) is False
  140. f = make_func('w, x=2, *args, y, z=4')
  141. assert check_valid(f) is incomplete
  142. assert check_valid(f, 1) is incomplete
  143. assert check_valid(f, 1, y=3)
  144. f = make_func('a, b, c=3, d=4, *args, e=5, f=6, g, h')
  145. assert check_valid(f) is incomplete
  146. assert check_valid(f, 1) is incomplete
  147. assert check_valid(f, 1, 2) is incomplete
  148. assert check_valid(f, 1, 2, g=7) is incomplete
  149. assert check_valid(f, 1, 2, g=7, h=8)
  150. assert check_valid(f, 1, 2, 3, 4, 5, 6, 7, 8, 9) is incomplete
  151. f = make_func('a: int, b: float')
  152. assert check_valid(f) is incomplete
  153. assert check_valid(f, 1) is incomplete
  154. assert check_valid(f, b=1) is incomplete
  155. assert check_valid(f, 1, 2)
  156. f = make_func('(a: int, b: float) -> float')
  157. assert check_valid(f) is incomplete
  158. assert check_valid(f, 1) is incomplete
  159. assert check_valid(f, b=1) is incomplete
  160. assert check_valid(f, 1, 2)
  161. f.__signature__ = 34
  162. assert check_valid(f) is False
  163. class RaisesValueError(object):
  164. def __call__(self):
  165. pass
  166. @property
  167. def __signature__(self):
  168. raise ValueError('Testing Python 3.4')
  169. f = RaisesValueError()
  170. assert check_valid(f) is None
  171. def test_is_partial():
  172. test_is_valid(check_valid=is_partial_args, incomplete=True)
  173. test_is_valid_py3(check_valid=is_partial_args, incomplete=True)
  174. def test_is_valid_curry():
  175. def check_curry(func, args, kwargs, incomplete=True):
  176. try:
  177. curry(func)(*args, **kwargs)
  178. curry(func, *args)(**kwargs)
  179. curry(func, **kwargs)(*args)
  180. curry(func, *args, **kwargs)()
  181. if not isinstance(func, type(lambda: None)):
  182. return None
  183. return incomplete
  184. except ValueError:
  185. return True
  186. except TypeError:
  187. return False
  188. check_valid = functools.partial(check_curry, incomplete=True)
  189. test_is_valid(check_valid=check_valid, incomplete=True)
  190. test_is_valid_py3(check_valid=check_valid, incomplete=True)
  191. check_valid = functools.partial(check_curry, incomplete=False)
  192. test_is_valid(check_valid=check_valid, incomplete=False)
  193. test_is_valid_py3(check_valid=check_valid, incomplete=False)
  194. def test_func_keyword():
  195. def f(func=None):
  196. pass
  197. assert is_valid_args(f, (), {})
  198. assert is_valid_args(f, (None,), {})
  199. assert is_valid_args(f, (), {'func': None})
  200. assert is_valid_args(f, (None,), {'func': None}) is False
  201. assert is_partial_args(f, (), {})
  202. assert is_partial_args(f, (None,), {})
  203. assert is_partial_args(f, (), {'func': None})
  204. assert is_partial_args(f, (None,), {'func': None}) is False
  205. def test_has_unknown_args():
  206. assert has_varargs(1) is False
  207. assert has_varargs(map)
  208. assert has_varargs(make_func('')) is False
  209. assert has_varargs(make_func('x, y, z')) is False
  210. assert has_varargs(make_func('*args'))
  211. assert has_varargs(make_func('**kwargs')) is False
  212. assert has_varargs(make_func('x, y, *args, **kwargs'))
  213. assert has_varargs(make_func('x, y, z=1')) is False
  214. assert has_varargs(make_func('x, y, z=1, **kwargs')) is False
  215. if PY3:
  216. f = make_func('*args')
  217. f.__signature__ = 34
  218. assert has_varargs(f) is False
  219. class RaisesValueError(object):
  220. def __call__(self):
  221. pass
  222. @property
  223. def __signature__(self):
  224. raise ValueError('Testing Python 3.4')
  225. f = RaisesValueError()
  226. assert has_varargs(f) is None
  227. def test_num_required_args():
  228. assert num_required_args(lambda: None) == 0
  229. assert num_required_args(lambda x: None) == 1
  230. assert num_required_args(lambda x, *args: None) == 1
  231. assert num_required_args(lambda x, **kwargs: None) == 1
  232. assert num_required_args(lambda x, y, *args, **kwargs: None) == 2
  233. assert num_required_args(map) == 2
  234. assert num_required_args(dict) is None
  235. def test_has_keywords():
  236. assert has_keywords(lambda: None) is False
  237. assert has_keywords(lambda x: None) is False
  238. assert has_keywords(lambda x=1: None)
  239. assert has_keywords(lambda **kwargs: None)
  240. assert has_keywords(int)
  241. assert has_keywords(sorted)
  242. assert has_keywords(max)
  243. assert has_keywords(map) is False
  244. assert has_keywords(bytearray) is None
  245. def test_has_varargs():
  246. assert has_varargs(lambda: None) is False
  247. assert has_varargs(lambda *args: None)
  248. assert has_varargs(lambda **kwargs: None) is False
  249. assert has_varargs(map)
  250. if PY3:
  251. assert has_varargs(max) is None
  252. def test_is_arity():
  253. assert is_arity(0, lambda: None)
  254. assert is_arity(1, lambda: None) is False
  255. assert is_arity(1, lambda x: None)
  256. assert is_arity(3, lambda x, y, z: None)
  257. assert is_arity(1, lambda x, *args: None) is False
  258. assert is_arity(1, lambda x, **kwargs: None) is False
  259. assert is_arity(1, all)
  260. assert is_arity(2, map) is False
  261. assert is_arity(2, range) is None
  262. def test_introspect_curry_valid_py3(check_valid=is_valid_args, incomplete=False):
  263. if not PY3:
  264. return
  265. orig_check_valid = check_valid
  266. check_valid = lambda _func, *args, **kwargs: orig_check_valid(_func, args, kwargs)
  267. f = toolz.curry(make_func('x, y, z=0'))
  268. assert check_valid(f)
  269. assert check_valid(f, 1)
  270. assert check_valid(f, 1, 2)
  271. assert check_valid(f, 1, 2, 3)
  272. assert check_valid(f, 1, 2, 3, 4) is False
  273. assert check_valid(f, invalid_keyword=True) is False
  274. assert check_valid(f(1))
  275. assert check_valid(f(1), 2)
  276. assert check_valid(f(1), 2, 3)
  277. assert check_valid(f(1), 2, 3, 4) is False
  278. assert check_valid(f(1), x=2) is False
  279. assert check_valid(f(1), y=2)
  280. assert check_valid(f(x=1), 2) is False
  281. assert check_valid(f(x=1), y=2)
  282. assert check_valid(f(y=2), 1)
  283. assert check_valid(f(y=2), 1, z=3)
  284. assert check_valid(f(y=2), 1, 3) is False
  285. f = toolz.curry(make_func('x, y, z=0'), 1, x=1)
  286. assert check_valid(f) is False
  287. assert check_valid(f, z=3) is False
  288. f = toolz.curry(make_func('x, y, *args, z'))
  289. assert check_valid(f)
  290. assert check_valid(f, 0)
  291. assert check_valid(f(1), 0)
  292. assert check_valid(f(1, 2), 0)
  293. assert check_valid(f(1, 2, 3), 0)
  294. assert check_valid(f(1, 2, 3, 4), 0)
  295. assert check_valid(f(1, 2, 3, 4), z=4)
  296. assert check_valid(f(x=1))
  297. assert check_valid(f(x=1), 1) is False
  298. assert check_valid(f(x=1), y=2)
  299. def test_introspect_curry_partial_py3():
  300. test_introspect_curry_valid_py3(check_valid=is_partial_args, incomplete=True)
  301. def test_introspect_curry_py3():
  302. if not PY3:
  303. return
  304. f = toolz.curry(make_func(''))
  305. assert num_required_args(f) == 0
  306. assert is_arity(0, f)
  307. assert has_varargs(f) is False
  308. assert has_keywords(f) is False
  309. f = toolz.curry(make_func('x'))
  310. assert num_required_args(f) == 0
  311. assert is_arity(0, f) is False
  312. assert is_arity(1, f) is False
  313. assert has_varargs(f) is False
  314. assert has_keywords(f) # A side-effect of being curried
  315. f = toolz.curry(make_func('x, y, z=0'))
  316. assert num_required_args(f) == 0
  317. assert is_arity(0, f) is False
  318. assert is_arity(1, f) is False
  319. assert is_arity(2, f) is False
  320. assert is_arity(3, f) is False
  321. assert has_varargs(f) is False
  322. assert has_keywords(f)
  323. f = toolz.curry(make_func('*args, **kwargs'))
  324. assert num_required_args(f) == 0
  325. assert has_varargs(f)
  326. assert has_keywords(f)
  327. def test_introspect_builtin_modules():
  328. mods = [builtins, functools, itertools, operator, toolz,
  329. toolz.functoolz, toolz.itertoolz, toolz.dicttoolz, toolz.recipes]
  330. blacklist = set()
  331. def add_blacklist(mod, attr):
  332. if hasattr(mod, attr):
  333. blacklist.add(getattr(mod, attr))
  334. add_blacklist(builtins, 'basestring')
  335. add_blacklist(builtins, 'breakpoint')
  336. add_blacklist(builtins, 'NoneType')
  337. add_blacklist(builtins, '__metaclass__')
  338. add_blacklist(builtins, 'sequenceiterator')
  339. def is_missing(modname, name, func):
  340. if name.startswith('_') and not name.startswith('__'):
  341. return False
  342. if name.startswith('__pyx_unpickle_') or name.endswith('_cython__'):
  343. return False
  344. try:
  345. if issubclass(func, BaseException):
  346. return False
  347. except TypeError:
  348. pass
  349. try:
  350. return (callable(func)
  351. and func.__module__ is not None
  352. and modname in func.__module__
  353. and is_partial_args(func, (), {}) is not True
  354. and func not in blacklist)
  355. except AttributeError:
  356. return False
  357. missing = {}
  358. for mod in mods:
  359. modname = mod.__name__
  360. for name, func in vars(mod).items():
  361. if is_missing(modname, name, func):
  362. if modname not in missing:
  363. missing[modname] = []
  364. missing[modname].append(name)
  365. if missing:
  366. messages = []
  367. for modname, names in sorted(missing.items()):
  368. msg = '{0}:\n {1}'.format(modname, '\n '.join(sorted(names)))
  369. messages.append(msg)
  370. message = 'Missing introspection for the following callables:\n\n'
  371. raise AssertionError(message + '\n\n'.join(messages))
  372. def test_inspect_signature_property():
  373. if not PY3:
  374. return
  375. # By adding AddX to our signature registry, we can inspect the class
  376. # itself and objects of the class. `inspect.signature` doesn't like
  377. # it when `obj.__signature__` is a property.
  378. class AddX(object):
  379. def __init__(self, func):
  380. self.func = func
  381. def __call__(self, addx, *args, **kwargs):
  382. return addx + self.func(*args, **kwargs)
  383. @property
  384. def __signature__(self):
  385. sig = inspect.signature(self.func)
  386. params = list(sig.parameters.values())
  387. kind = inspect.Parameter.POSITIONAL_OR_KEYWORD
  388. newparam = inspect.Parameter('addx', kind)
  389. params = [newparam] + params
  390. return sig.replace(parameters=params)
  391. addx = AddX(lambda x: x)
  392. sig = inspect.signature(addx)
  393. assert sig == inspect.Signature(parameters=[
  394. inspect.Parameter('addx', inspect.Parameter.POSITIONAL_OR_KEYWORD),
  395. inspect.Parameter('x', inspect.Parameter.POSITIONAL_OR_KEYWORD)])
  396. assert num_required_args(AddX) is False
  397. _sigs.signatures[AddX] = (_sigs.expand_sig((0, lambda func: None)),)
  398. assert num_required_args(AddX) == 1
  399. del _sigs.signatures[AddX]
  400. def test_inspect_wrapped_property():
  401. class Wrapped(object):
  402. def __init__(self, func):
  403. self.func = func
  404. def __call__(self, *args, **kwargs):
  405. return self.func(*args, **kwargs)
  406. @property
  407. def __wrapped__(self):
  408. return self.func
  409. func = lambda x: x
  410. wrapped = Wrapped(func)
  411. if PY3:
  412. assert inspect.signature(func) == inspect.signature(wrapped)
  413. assert num_required_args(Wrapped) == (False if PY33 else None)
  414. _sigs.signatures[Wrapped] = (_sigs.expand_sig((0, lambda func: None)),)
  415. assert num_required_args(Wrapped) == 1