Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/toolz/_signatures.py: 46%
144 statements
« prev ^ index » next coverage.py v7.2.2, created at 2023-03-26 06:47 +0000
« prev ^ index » next coverage.py v7.2.2, created at 2023-03-26 06:47 +0000
1"""Internal module for better introspection of builtins.
3The main functions are ``is_builtin_valid_args``, ``is_builtin_partial_args``,
4and ``has_unknown_args``. Other functions in this module support these three.
6Notably, we create a ``signatures`` registry to enable introspection of
7builtin functions in any Python version. This includes builtins that
8have more than one valid signature. Currently, the registry includes
9builtins from ``builtins``, ``functools``, ``itertools``, and ``operator``
10modules. More can be added as requested. We don't guarantee full coverage.
12Everything in this module should be regarded as implementation details.
13Users should try to not use this module directly.
14"""
15import functools
16import inspect
17import itertools
18import operator
19from importlib import import_module
21from .functoolz import (is_partial_args, is_arity, has_varargs,
22 has_keywords, num_required_args)
24import builtins
26# We mock builtin callables using lists of tuples with lambda functions.
27#
28# The tuple spec is (num_position_args, lambda_func, keyword_only_args).
29#
30# num_position_args:
31# - The number of positional-only arguments. If not specified,
32# all positional arguments are considered positional-only.
33#
34# lambda_func:
35# - lambda function that matches a signature of a builtin, but does
36# not include keyword-only arguments.
37#
38# keyword_only_args: (optional)
39# - Tuple of keyword-only arguments.
41module_info = {}
43module_info[builtins] = dict(
44 abs=[
45 lambda x: None],
46 all=[
47 lambda iterable: None],
48 anext=[
49 lambda aiterator: None,
50 lambda aiterator, default: None],
51 any=[
52 lambda iterable: None],
53 apply=[
54 lambda object: None,
55 lambda object, args: None,
56 lambda object, args, kwargs: None],
57 ascii=[
58 lambda obj: None],
59 bin=[
60 lambda number: None],
61 bool=[
62 lambda x=False: None],
63 buffer=[
64 lambda object: None,
65 lambda object, offset: None,
66 lambda object, offset, size: None],
67 bytearray=[
68 lambda: None,
69 lambda int: None,
70 lambda string, encoding='utf8', errors='strict': None],
71 callable=[
72 lambda obj: None],
73 chr=[
74 lambda i: None],
75 classmethod=[
76 lambda function: None],
77 cmp=[
78 lambda x, y: None],
79 coerce=[
80 lambda x, y: None],
81 complex=[
82 lambda real=0, imag=0: None],
83 delattr=[
84 lambda obj, name: None],
85 dict=[
86 lambda **kwargs: None,
87 lambda mapping, **kwargs: None],
88 dir=[
89 lambda: None,
90 lambda object: None],
91 divmod=[
92 lambda x, y: None],
93 enumerate=[
94 (0, lambda iterable, start=0: None)],
95 eval=[
96 lambda source: None,
97 lambda source, globals: None,
98 lambda source, globals, locals: None],
99 execfile=[
100 lambda filename: None,
101 lambda filename, globals: None,
102 lambda filename, globals, locals: None],
103 file=[
104 (0, lambda name, mode='r', buffering=-1: None)],
105 filter=[
106 lambda function, iterable: None],
107 float=[
108 lambda x=0.0: None],
109 format=[
110 lambda value: None,
111 lambda value, format_spec: None],
112 frozenset=[
113 lambda: None,
114 lambda iterable: None],
115 getattr=[
116 lambda object, name: None,
117 lambda object, name, default: None],
118 globals=[
119 lambda: None],
120 hasattr=[
121 lambda obj, name: None],
122 hash=[
123 lambda obj: None],
124 hex=[
125 lambda number: None],
126 id=[
127 lambda obj: None],
128 input=[
129 lambda: None,
130 lambda prompt: None],
131 int=[
132 lambda x=0: None,
133 (0, lambda x, base=10: None)],
134 intern=[
135 lambda string: None],
136 isinstance=[
137 lambda obj, class_or_tuple: None],
138 issubclass=[
139 lambda cls, class_or_tuple: None],
140 iter=[
141 lambda iterable: None,
142 lambda callable, sentinel: None],
143 len=[
144 lambda obj: None],
145 list=[
146 lambda: None,
147 lambda iterable: None],
148 locals=[
149 lambda: None],
150 long=[
151 lambda x=0: None,
152 (0, lambda x, base=10: None)],
153 map=[
154 lambda func, sequence, *iterables: None],
155 memoryview=[
156 (0, lambda object: None)],
157 next=[
158 lambda iterator: None,
159 lambda iterator, default: None],
160 object=[
161 lambda: None],
162 oct=[
163 lambda number: None],
164 ord=[
165 lambda c: None],
166 pow=[
167 lambda x, y: None,
168 lambda x, y, z: None],
169 property=[
170 lambda fget=None, fset=None, fdel=None, doc=None: None],
171 range=[
172 lambda stop: None,
173 lambda start, stop: None,
174 lambda start, stop, step: None],
175 raw_input=[
176 lambda: None,
177 lambda prompt: None],
178 reduce=[
179 lambda function, sequence: None,
180 lambda function, sequence, initial: None],
181 reload=[
182 lambda module: None],
183 repr=[
184 lambda obj: None],
185 reversed=[
186 lambda sequence: None],
187 round=[
188 (0, lambda number, ndigits=0: None)],
189 set=[
190 lambda: None,
191 lambda iterable: None],
192 setattr=[
193 lambda obj, name, value: None],
194 slice=[
195 lambda stop: None,
196 lambda start, stop: None,
197 lambda start, stop, step: None],
198 staticmethod=[
199 lambda function: None],
200 sum=[
201 lambda iterable: None,
202 lambda iterable, start: None],
203 super=[
204 lambda type: None,
205 lambda type, obj: None],
206 tuple=[
207 lambda: None,
208 lambda iterable: None],
209 type=[
210 lambda object: None,
211 lambda name, bases, dict: None],
212 unichr=[
213 lambda i: None],
214 unicode=[
215 lambda object: None,
216 lambda string='', encoding='utf8', errors='strict': None],
217 vars=[
218 lambda: None,
219 lambda object: None],
220 xrange=[
221 lambda stop: None,
222 lambda start, stop: None,
223 lambda start, stop, step: None],
224 zip=[
225 lambda *iterables: None],
226 __build_class__=[
227 (2, lambda func, name, *bases, **kwds: None, ('metaclass',))],
228 __import__=[
229 (0, lambda name, globals=None, locals=None, fromlist=None,
230 level=None: None)],
231)
232module_info[builtins]['exec'] = [
233 lambda source: None,
234 lambda source, globals: None,
235 lambda source, globals, locals: None]
237module_info[builtins].update(
238 breakpoint=[
239 lambda *args, **kws: None],
240 bytes=[
241 lambda: None,
242 lambda int: None,
243 lambda string, encoding='utf8', errors='strict': None],
244 compile=[
245 (0, lambda source, filename, mode, flags=0,
246 dont_inherit=False, optimize=-1: None)],
247 max=[
248 (1, lambda iterable: None, ('default', 'key',)),
249 (1, lambda arg1, arg2, *args: None, ('key',))],
250 min=[
251 (1, lambda iterable: None, ('default', 'key',)),
252 (1, lambda arg1, arg2, *args: None, ('key',))],
253 open=[
254 (0, lambda file, mode='r', buffering=-1, encoding=None,
255 errors=None, newline=None, closefd=True, opener=None: None)],
256 sorted=[
257 (1, lambda iterable: None, ('key', 'reverse'))],
258 str=[
259 lambda object='', encoding='utf', errors='strict': None],
260)
261module_info[builtins]['print'] = [
262 (0, lambda *args: None, ('sep', 'end', 'file', 'flush',))]
265module_info[functools] = dict(
266 cmp_to_key=[
267 (0, lambda mycmp: None)],
268 partial=[
269 lambda func, *args, **kwargs: None],
270 partialmethod=[
271 lambda func, *args, **kwargs: None],
272 reduce=[
273 lambda function, sequence: None,
274 lambda function, sequence, initial: None],
275)
277module_info[itertools] = dict(
278 accumulate=[
279 (0, lambda iterable, func=None: None)],
280 chain=[
281 lambda *iterables: None],
282 combinations=[
283 (0, lambda iterable, r: None)],
284 combinations_with_replacement=[
285 (0, lambda iterable, r: None)],
286 compress=[
287 (0, lambda data, selectors: None)],
288 count=[
289 lambda start=0, step=1: None],
290 cycle=[
291 lambda iterable: None],
292 dropwhile=[
293 lambda predicate, iterable: None],
294 filterfalse=[
295 lambda function, sequence: None],
296 groupby=[
297 (0, lambda iterable, key=None: None)],
298 ifilter=[
299 lambda function, sequence: None],
300 ifilterfalse=[
301 lambda function, sequence: None],
302 imap=[
303 lambda func, sequence, *iterables: None],
304 islice=[
305 lambda iterable, stop: None,
306 lambda iterable, start, stop: None,
307 lambda iterable, start, stop, step: None],
308 izip=[
309 lambda *iterables: None],
310 izip_longest=[
311 (0, lambda *iterables: None, ('fillvalue',))],
312 permutations=[
313 (0, lambda iterable, r=0: None)],
314 repeat=[
315 (0, lambda object, times=0: None)],
316 starmap=[
317 lambda function, sequence: None],
318 takewhile=[
319 lambda predicate, iterable: None],
320 tee=[
321 lambda iterable: None,
322 lambda iterable, n: None],
323 zip_longest=[
324 (0, lambda *iterables: None, ('fillvalue',))],
325)
327module_info[itertools].update(
328 product=[
329 (0, lambda *iterables: None, ('repeat',))],
330)
333module_info[operator] = dict(
334 __abs__=[
335 lambda a: None],
336 __add__=[
337 lambda a, b: None],
338 __and__=[
339 lambda a, b: None],
340 __concat__=[
341 lambda a, b: None],
342 __contains__=[
343 lambda a, b: None],
344 __delitem__=[
345 lambda a, b: None],
346 __delslice__=[
347 lambda a, b, c: None],
348 __div__=[
349 lambda a, b: None],
350 __eq__=[
351 lambda a, b: None],
352 __floordiv__=[
353 lambda a, b: None],
354 __ge__=[
355 lambda a, b: None],
356 __getitem__=[
357 lambda a, b: None],
358 __getslice__=[
359 lambda a, b, c: None],
360 __gt__=[
361 lambda a, b: None],
362 __iadd__=[
363 lambda a, b: None],
364 __iand__=[
365 lambda a, b: None],
366 __iconcat__=[
367 lambda a, b: None],
368 __idiv__=[
369 lambda a, b: None],
370 __ifloordiv__=[
371 lambda a, b: None],
372 __ilshift__=[
373 lambda a, b: None],
374 __imatmul__=[
375 lambda a, b: None],
376 __imod__=[
377 lambda a, b: None],
378 __imul__=[
379 lambda a, b: None],
380 __index__=[
381 lambda a: None],
382 __inv__=[
383 lambda a: None],
384 __invert__=[
385 lambda a: None],
386 __ior__=[
387 lambda a, b: None],
388 __ipow__=[
389 lambda a, b: None],
390 __irepeat__=[
391 lambda a, b: None],
392 __irshift__=[
393 lambda a, b: None],
394 __isub__=[
395 lambda a, b: None],
396 __itruediv__=[
397 lambda a, b: None],
398 __ixor__=[
399 lambda a, b: None],
400 __le__=[
401 lambda a, b: None],
402 __lshift__=[
403 lambda a, b: None],
404 __lt__=[
405 lambda a, b: None],
406 __matmul__=[
407 lambda a, b: None],
408 __mod__=[
409 lambda a, b: None],
410 __mul__=[
411 lambda a, b: None],
412 __ne__=[
413 lambda a, b: None],
414 __neg__=[
415 lambda a: None],
416 __not__=[
417 lambda a: None],
418 __or__=[
419 lambda a, b: None],
420 __pos__=[
421 lambda a: None],
422 __pow__=[
423 lambda a, b: None],
424 __repeat__=[
425 lambda a, b: None],
426 __rshift__=[
427 lambda a, b: None],
428 __setitem__=[
429 lambda a, b, c: None],
430 __setslice__=[
431 lambda a, b, c, d: None],
432 __sub__=[
433 lambda a, b: None],
434 __truediv__=[
435 lambda a, b: None],
436 __xor__=[
437 lambda a, b: None],
438 _abs=[
439 lambda x: None],
440 _compare_digest=[
441 lambda a, b: None],
442 abs=[
443 lambda a: None],
444 add=[
445 lambda a, b: None],
446 and_=[
447 lambda a, b: None],
448 attrgetter=[
449 lambda attr, *args: None],
450 concat=[
451 lambda a, b: None],
452 contains=[
453 lambda a, b: None],
454 countOf=[
455 lambda a, b: None],
456 delitem=[
457 lambda a, b: None],
458 delslice=[
459 lambda a, b, c: None],
460 div=[
461 lambda a, b: None],
462 eq=[
463 lambda a, b: None],
464 floordiv=[
465 lambda a, b: None],
466 ge=[
467 lambda a, b: None],
468 getitem=[
469 lambda a, b: None],
470 getslice=[
471 lambda a, b, c: None],
472 gt=[
473 lambda a, b: None],
474 iadd=[
475 lambda a, b: None],
476 iand=[
477 lambda a, b: None],
478 iconcat=[
479 lambda a, b: None],
480 idiv=[
481 lambda a, b: None],
482 ifloordiv=[
483 lambda a, b: None],
484 ilshift=[
485 lambda a, b: None],
486 imatmul=[
487 lambda a, b: None],
488 imod=[
489 lambda a, b: None],
490 imul=[
491 lambda a, b: None],
492 index=[
493 lambda a: None],
494 indexOf=[
495 lambda a, b: None],
496 inv=[
497 lambda a: None],
498 invert=[
499 lambda a: None],
500 ior=[
501 lambda a, b: None],
502 ipow=[
503 lambda a, b: None],
504 irepeat=[
505 lambda a, b: None],
506 irshift=[
507 lambda a, b: None],
508 is_=[
509 lambda a, b: None],
510 is_not=[
511 lambda a, b: None],
512 isCallable=[
513 lambda a: None],
514 isMappingType=[
515 lambda a: None],
516 isNumberType=[
517 lambda a: None],
518 isSequenceType=[
519 lambda a: None],
520 isub=[
521 lambda a, b: None],
522 itemgetter=[
523 lambda item, *args: None],
524 itruediv=[
525 lambda a, b: None],
526 ixor=[
527 lambda a, b: None],
528 le=[
529 lambda a, b: None],
530 length_hint=[
531 lambda obj: None,
532 lambda obj, default: None],
533 lshift=[
534 lambda a, b: None],
535 lt=[
536 lambda a, b: None],
537 matmul=[
538 lambda a, b: None],
539 methodcaller=[
540 lambda name, *args, **kwargs: None],
541 mod=[
542 lambda a, b: None],
543 mul=[
544 lambda a, b: None],
545 ne=[
546 lambda a, b: None],
547 neg=[
548 lambda a: None],
549 not_=[
550 lambda a: None],
551 or_=[
552 lambda a, b: None],
553 pos=[
554 lambda a: None],
555 pow=[
556 lambda a, b: None],
557 repeat=[
558 lambda a, b: None],
559 rshift=[
560 lambda a, b: None],
561 sequenceIncludes=[
562 lambda a, b: None],
563 setitem=[
564 lambda a, b, c: None],
565 setslice=[
566 lambda a, b, c, d: None],
567 sub=[
568 lambda a, b: None],
569 truediv=[
570 lambda a, b: None],
571 truth=[
572 lambda a: None],
573 xor=[
574 lambda a, b: None],
575)
577module_info['toolz'] = dict(
578 curry=[
579 (0, lambda *args, **kwargs: None)],
580 excepts=[
581 (0, lambda exc, func, handler=None: None)],
582 flip=[
583 (0, lambda func=None, a=None, b=None: None)],
584 juxt=[
585 (0, lambda *funcs: None)],
586 memoize=[
587 (0, lambda func=None, cache=None, key=None: None)],
588)
590module_info['toolz.functoolz'] = dict(
591 Compose=[
592 (0, lambda funcs: None)],
593 InstanceProperty=[
594 (0, lambda fget=None, fset=None, fdel=None, doc=None,
595 classval=None: None)],
596)
599def num_pos_args(sigspec):
600 """ Return the number of positional arguments. ``f(x, y=1)`` has 1"""
601 return sum(1 for x in sigspec.parameters.values()
602 if x.kind == x.POSITIONAL_OR_KEYWORD
603 and x.default is x.empty)
606def get_exclude_keywords(num_pos_only, sigspec):
607 """ Return the names of position-only arguments if func has **kwargs"""
608 if num_pos_only == 0:
609 return ()
610 has_kwargs = any(x.kind == x.VAR_KEYWORD
611 for x in sigspec.parameters.values())
612 if not has_kwargs:
613 return ()
614 pos_args = list(sigspec.parameters.values())[:num_pos_only]
615 return tuple(x.name for x in pos_args)
618def signature_or_spec(func):
619 try:
620 return inspect.signature(func)
621 except (ValueError, TypeError):
622 return None
625def expand_sig(sig):
626 """ Convert the signature spec in ``module_info`` to add to ``signatures``
628 The input signature spec is one of:
629 - ``lambda_func``
630 - ``(num_position_args, lambda_func)``
631 - ``(num_position_args, lambda_func, keyword_only_args)``
633 The output signature spec is:
634 ``(num_position_args, lambda_func, keyword_exclude, sigspec)``
636 where ``keyword_exclude`` includes keyword only arguments and, if variadic
637 keywords is present, the names of position-only argument. The latter is
638 included to support builtins such as ``partial(func, *args, **kwargs)``,
639 which allows ``func=`` to be used as a keyword even though it's the name
640 of a positional argument.
641 """
642 if isinstance(sig, tuple):
643 if len(sig) == 3:
644 num_pos_only, func, keyword_only = sig
645 assert isinstance(sig[-1], tuple)
646 else:
647 num_pos_only, func = sig
648 keyword_only = ()
649 sigspec = signature_or_spec(func)
650 else:
651 func = sig
652 sigspec = signature_or_spec(func)
653 num_pos_only = num_pos_args(sigspec)
654 keyword_only = ()
655 keyword_exclude = get_exclude_keywords(num_pos_only, sigspec)
656 return num_pos_only, func, keyword_only + keyword_exclude, sigspec
659signatures = {}
662def create_signature_registry(module_info=module_info, signatures=signatures):
663 for module, info in module_info.items():
664 if isinstance(module, str):
665 module = import_module(module)
666 for name, sigs in info.items():
667 if hasattr(module, name):
668 new_sigs = tuple(expand_sig(sig) for sig in sigs)
669 signatures[getattr(module, name)] = new_sigs
672def check_valid(sig, args, kwargs):
673 """ Like ``is_valid_args`` for the given signature spec"""
674 num_pos_only, func, keyword_exclude, sigspec = sig
675 if len(args) < num_pos_only:
676 return False
677 if keyword_exclude:
678 kwargs = dict(kwargs)
679 for item in keyword_exclude:
680 kwargs.pop(item, None)
681 try:
682 func(*args, **kwargs)
683 return True
684 except TypeError:
685 return False
688def _is_valid_args(func, args, kwargs):
689 """ Like ``is_valid_args`` for builtins in our ``signatures`` registry"""
690 if func not in signatures:
691 return None
692 sigs = signatures[func]
693 return any(check_valid(sig, args, kwargs) for sig in sigs)
696def check_partial(sig, args, kwargs):
697 """ Like ``is_partial_args`` for the given signature spec"""
698 num_pos_only, func, keyword_exclude, sigspec = sig
699 if len(args) < num_pos_only:
700 pad = (None,) * (num_pos_only - len(args))
701 args = args + pad
702 if keyword_exclude:
703 kwargs = dict(kwargs)
704 for item in keyword_exclude:
705 kwargs.pop(item, None)
706 return is_partial_args(func, args, kwargs, sigspec)
709def _is_partial_args(func, args, kwargs):
710 """ Like ``is_partial_args`` for builtins in our ``signatures`` registry"""
711 if func not in signatures:
712 return None
713 sigs = signatures[func]
714 return any(check_partial(sig, args, kwargs) for sig in sigs)
717def check_arity(n, sig):
718 num_pos_only, func, keyword_exclude, sigspec = sig
719 if keyword_exclude or num_pos_only > n:
720 return False
721 return is_arity(n, func, sigspec)
724def _is_arity(n, func):
725 if func not in signatures:
726 return None
727 sigs = signatures[func]
728 checks = [check_arity(n, sig) for sig in sigs]
729 if all(checks):
730 return True
731 elif any(checks):
732 return None
733 return False
736def check_varargs(sig):
737 num_pos_only, func, keyword_exclude, sigspec = sig
738 return has_varargs(func, sigspec)
741def _has_varargs(func):
742 if func not in signatures:
743 return None
744 sigs = signatures[func]
745 checks = [check_varargs(sig) for sig in sigs]
746 if all(checks):
747 return True
748 elif any(checks):
749 return None
750 return False
753def check_keywords(sig):
754 num_pos_only, func, keyword_exclude, sigspec = sig
755 if keyword_exclude:
756 return True
757 return has_keywords(func, sigspec)
760def _has_keywords(func):
761 if func not in signatures:
762 return None
763 sigs = signatures[func]
764 checks = [check_keywords(sig) for sig in sigs]
765 if all(checks):
766 return True
767 elif any(checks):
768 return None
769 return False
772def check_required_args(sig):
773 num_pos_only, func, keyword_exclude, sigspec = sig
774 return num_required_args(func, sigspec)
777def _num_required_args(func):
778 if func not in signatures:
779 return None
780 sigs = signatures[func]
781 vals = [check_required_args(sig) for sig in sigs]
782 val = vals[0]
783 if all(x == val for x in vals):
784 return val
785 return None