Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/toolz/_signatures.py: 46%
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
Shortcuts on this page
r m x toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
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 frozendict=[
113 lambda **kwargs: None,
114 lambda mapping, **kwargs: None],
115 frozenset=[
116 lambda: None,
117 lambda iterable: None],
118 getattr=[
119 lambda object, name: None,
120 lambda object, name, default: None],
121 globals=[
122 lambda: None],
123 hasattr=[
124 lambda obj, name: None],
125 hash=[
126 lambda obj: None],
127 hex=[
128 lambda number: None],
129 id=[
130 lambda obj: None],
131 input=[
132 lambda: None,
133 lambda prompt: None],
134 int=[
135 lambda x=0: None,
136 (0, lambda x, base=10: None)],
137 intern=[
138 lambda string: None],
139 isinstance=[
140 lambda obj, class_or_tuple: None],
141 issubclass=[
142 lambda cls, class_or_tuple: None],
143 iter=[
144 lambda iterable: None,
145 lambda callable, sentinel: None],
146 len=[
147 lambda obj: None],
148 list=[
149 lambda: None,
150 lambda iterable: None],
151 locals=[
152 lambda: None],
153 long=[
154 lambda x=0: None,
155 (0, lambda x, base=10: None)],
156 map=[
157 lambda func, sequence, *iterables: None],
158 memoryview=[
159 (0, lambda object: None)],
160 next=[
161 lambda iterator: None,
162 lambda iterator, default: None],
163 object=[
164 lambda: None],
165 oct=[
166 lambda number: None],
167 ord=[
168 lambda c: None],
169 pow=[
170 lambda x, y: None,
171 lambda x, y, z: None],
172 property=[
173 lambda fget=None, fset=None, fdel=None, doc=None: None],
174 range=[
175 lambda stop: None,
176 lambda start, stop: None,
177 lambda start, stop, step: None],
178 raw_input=[
179 lambda: None,
180 lambda prompt: None],
181 reduce=[
182 lambda function, sequence: None,
183 lambda function, sequence, initial: None],
184 reload=[
185 lambda module: None],
186 repr=[
187 lambda obj: None],
188 reversed=[
189 lambda sequence: None],
190 round=[
191 (0, lambda number, ndigits=0: None)],
192 set=[
193 lambda: None,
194 lambda iterable: None],
195 setattr=[
196 lambda obj, name, value: None],
197 slice=[
198 lambda stop: None,
199 lambda start, stop: None,
200 lambda start, stop, step: None],
201 staticmethod=[
202 lambda function: None],
203 sum=[
204 lambda iterable: None,
205 lambda iterable, start: None],
206 super=[
207 lambda type: None,
208 lambda type, obj: None],
209 tuple=[
210 lambda: None,
211 lambda iterable: None],
212 type=[
213 lambda object: None,
214 lambda name, bases, dict: None],
215 unichr=[
216 lambda i: None],
217 unicode=[
218 lambda object: None,
219 lambda string='', encoding='utf8', errors='strict': None],
220 vars=[
221 lambda: None,
222 lambda object: None],
223 xrange=[
224 lambda stop: None,
225 lambda start, stop: None,
226 lambda start, stop, step: None],
227 zip=[
228 lambda *iterables: None],
229 __build_class__=[
230 (2, lambda func, name, *bases, **kwds: None, ('metaclass',))],
231 __import__=[
232 (0, lambda name, globals=None, locals=None, fromlist=None,
233 level=None: None)],
234)
235module_info[builtins]['exec'] = [
236 lambda source: None,
237 lambda source, globals: None,
238 lambda source, globals, locals: None]
240module_info[builtins].update(
241 breakpoint=[
242 lambda *args, **kws: None],
243 bytes=[
244 lambda: None,
245 lambda int: None,
246 lambda string, encoding='utf8', errors='strict': None],
247 compile=[
248 (0, lambda source, filename, mode, flags=0,
249 dont_inherit=False, optimize=-1: None)],
250 max=[
251 (1, lambda iterable: None, ('default', 'key',)),
252 (1, lambda arg1, arg2, *args: None, ('key',))],
253 min=[
254 (1, lambda iterable: None, ('default', 'key',)),
255 (1, lambda arg1, arg2, *args: None, ('key',))],
256 open=[
257 (0, lambda file, mode='r', buffering=-1, encoding=None,
258 errors=None, newline=None, closefd=True, opener=None: None)],
259 sorted=[
260 (1, lambda iterable: None, ('key', 'reverse'))],
261 str=[
262 lambda object='', encoding='utf', errors='strict': None],
263)
264module_info[builtins]['print'] = [
265 (0, lambda *args: None, ('sep', 'end', 'file', 'flush',))]
268module_info[functools] = dict(
269 cmp_to_key=[
270 (0, lambda mycmp: None)],
271 partial=[
272 lambda func, *args, **kwargs: None],
273 partialmethod=[
274 lambda func, *args, **kwargs: None],
275 reduce=[
276 lambda function, sequence: None,
277 lambda function, sequence, initial: None],
278)
280module_info[itertools] = dict(
281 accumulate=[
282 (0, lambda iterable, func=None: None)],
283 chain=[
284 lambda *iterables: None],
285 combinations=[
286 (0, lambda iterable, r: None)],
287 combinations_with_replacement=[
288 (0, lambda iterable, r: None)],
289 compress=[
290 (0, lambda data, selectors: None)],
291 count=[
292 lambda start=0, step=1: None],
293 cycle=[
294 lambda iterable: None],
295 dropwhile=[
296 lambda predicate, iterable: None],
297 filterfalse=[
298 lambda function, sequence: None],
299 groupby=[
300 (0, lambda iterable, key=None: None)],
301 ifilter=[
302 lambda function, sequence: None],
303 ifilterfalse=[
304 lambda function, sequence: None],
305 imap=[
306 lambda func, sequence, *iterables: None],
307 islice=[
308 lambda iterable, stop: None,
309 lambda iterable, start, stop: None,
310 lambda iterable, start, stop, step: None],
311 izip=[
312 lambda *iterables: None],
313 izip_longest=[
314 (0, lambda *iterables: None, ('fillvalue',))],
315 pairwise=[
316 lambda iterable: None],
317 permutations=[
318 (0, lambda iterable, r=0: None)],
319 product=[
320 (0, lambda *iterables: None, ('repeat',))],
321 repeat=[
322 (0, lambda object, times=0: None)],
323 starmap=[
324 lambda function, sequence: None],
325 takewhile=[
326 lambda predicate, iterable: None],
327 tee=[
328 lambda iterable: None,
329 lambda iterable, n: None],
330 zip_longest=[
331 (0, lambda *iterables: None, ('fillvalue',))],
332)
335module_info[operator] = dict(
336 __abs__=[
337 lambda a: None],
338 __add__=[
339 lambda a, b: None],
340 __and__=[
341 lambda a, b: None],
342 __concat__=[
343 lambda a, b: None],
344 __contains__=[
345 lambda a, b: None],
346 __delitem__=[
347 lambda a, b: None],
348 __delslice__=[
349 lambda a, b, c: None],
350 __div__=[
351 lambda a, b: None],
352 __eq__=[
353 lambda a, b: None],
354 __floordiv__=[
355 lambda a, b: None],
356 __ge__=[
357 lambda a, b: None],
358 __getitem__=[
359 lambda a, b: None],
360 __getslice__=[
361 lambda a, b, c: None],
362 __gt__=[
363 lambda a, b: None],
364 __iadd__=[
365 lambda a, b: None],
366 __iand__=[
367 lambda a, b: None],
368 __iconcat__=[
369 lambda a, b: None],
370 __idiv__=[
371 lambda a, b: None],
372 __ifloordiv__=[
373 lambda a, b: None],
374 __ilshift__=[
375 lambda a, b: None],
376 __imatmul__=[
377 lambda a, b: None],
378 __imod__=[
379 lambda a, b: None],
380 __imul__=[
381 lambda a, b: None],
382 __index__=[
383 lambda a: None],
384 __inv__=[
385 lambda a: None],
386 __invert__=[
387 lambda a: None],
388 __ior__=[
389 lambda a, b: None],
390 __ipow__=[
391 lambda a, b: None],
392 __irepeat__=[
393 lambda a, b: None],
394 __irshift__=[
395 lambda a, b: None],
396 __isub__=[
397 lambda a, b: None],
398 __itruediv__=[
399 lambda a, b: None],
400 __ixor__=[
401 lambda a, b: None],
402 __le__=[
403 lambda a, b: None],
404 __lshift__=[
405 lambda a, b: None],
406 __lt__=[
407 lambda a, b: None],
408 __matmul__=[
409 lambda a, b: None],
410 __mod__=[
411 lambda a, b: None],
412 __mul__=[
413 lambda a, b: None],
414 __ne__=[
415 lambda a, b: None],
416 __neg__=[
417 lambda a: None],
418 __not__=[
419 lambda a: None],
420 __or__=[
421 lambda a, b: None],
422 __pos__=[
423 lambda a: None],
424 __pow__=[
425 lambda a, b: None],
426 __repeat__=[
427 lambda a, b: None],
428 __rshift__=[
429 lambda a, b: None],
430 __setitem__=[
431 lambda a, b, c: None],
432 __setslice__=[
433 lambda a, b, c, d: None],
434 __sub__=[
435 lambda a, b: None],
436 __truediv__=[
437 lambda a, b: None],
438 __xor__=[
439 lambda a, b: None],
440 _abs=[
441 lambda x: None],
442 _compare_digest=[
443 lambda a, b: None],
444 abs=[
445 lambda a: None],
446 add=[
447 lambda a, b: None],
448 and_=[
449 lambda a, b: None],
450 attrgetter=[
451 lambda attr, *args: None],
452 concat=[
453 lambda a, b: None],
454 contains=[
455 lambda a, b: None],
456 countOf=[
457 lambda a, b: None],
458 delitem=[
459 lambda a, b: None],
460 delslice=[
461 lambda a, b, c: None],
462 div=[
463 lambda a, b: None],
464 eq=[
465 lambda a, b: None],
466 floordiv=[
467 lambda a, b: None],
468 ge=[
469 lambda a, b: None],
470 getitem=[
471 lambda a, b: None],
472 getslice=[
473 lambda a, b, c: None],
474 gt=[
475 lambda a, b: None],
476 iadd=[
477 lambda a, b: None],
478 iand=[
479 lambda a, b: None],
480 iconcat=[
481 lambda a, b: None],
482 idiv=[
483 lambda a, b: None],
484 ifloordiv=[
485 lambda a, b: None],
486 ilshift=[
487 lambda a, b: None],
488 imatmul=[
489 lambda a, b: None],
490 imod=[
491 lambda a, b: None],
492 imul=[
493 lambda a, b: None],
494 index=[
495 lambda a: None],
496 indexOf=[
497 lambda a, b: None],
498 inv=[
499 lambda a: None],
500 invert=[
501 lambda a: None],
502 ior=[
503 lambda a, b: None],
504 ipow=[
505 lambda a, b: None],
506 irepeat=[
507 lambda a, b: None],
508 irshift=[
509 lambda a, b: None],
510 is_=[
511 lambda a, b: None],
512 is_not=[
513 lambda a, b: None],
514 isCallable=[
515 lambda a: None],
516 isMappingType=[
517 lambda a: None],
518 isNumberType=[
519 lambda a: None],
520 isSequenceType=[
521 lambda a: None],
522 isub=[
523 lambda a, b: None],
524 itemgetter=[
525 lambda item, *args: None],
526 itruediv=[
527 lambda a, b: None],
528 ixor=[
529 lambda a, b: None],
530 le=[
531 lambda a, b: None],
532 length_hint=[
533 lambda obj: None,
534 lambda obj, default: None],
535 lshift=[
536 lambda a, b: None],
537 lt=[
538 lambda a, b: None],
539 matmul=[
540 lambda a, b: None],
541 methodcaller=[
542 lambda name, *args, **kwargs: None],
543 mod=[
544 lambda a, b: None],
545 mul=[
546 lambda a, b: None],
547 ne=[
548 lambda a, b: None],
549 neg=[
550 lambda a: None],
551 not_=[
552 lambda a: None],
553 or_=[
554 lambda a, b: None],
555 pos=[
556 lambda a: None],
557 pow=[
558 lambda a, b: None],
559 repeat=[
560 lambda a, b: None],
561 rshift=[
562 lambda a, b: None],
563 sequenceIncludes=[
564 lambda a, b: None],
565 setitem=[
566 lambda a, b, c: None],
567 setslice=[
568 lambda a, b, c, d: None],
569 sub=[
570 lambda a, b: None],
571 truediv=[
572 lambda a, b: None],
573 truth=[
574 lambda a: None],
575 xor=[
576 lambda a, b: None],
577)
579module_info['toolz'] = dict(
580 curry=[
581 (0, lambda *args, **kwargs: None)],
582 excepts=[
583 (0, lambda exc, func, handler=None: None)],
584 flip=[
585 (0, lambda func=None, a=None, b=None: None)],
586 juxt=[
587 (0, lambda *funcs: None)],
588 memoize=[
589 (0, lambda func=None, cache=None, key=None: None)],
590)
592module_info['toolz.functoolz'] = dict(
593 Compose=[
594 (0, lambda funcs: None)],
595 InstanceProperty=[
596 (0, lambda fget=None, fset=None, fdel=None, doc=None,
597 classval=None: None)],
598)
601def num_pos_args(sigspec):
602 """ Return the number of positional arguments. ``f(x, y=1)`` has 1"""
603 return sum(1 for x in sigspec.parameters.values()
604 if x.kind == x.POSITIONAL_OR_KEYWORD
605 and x.default is x.empty)
608def get_exclude_keywords(num_pos_only, sigspec):
609 """ Return the names of position-only arguments if func has **kwargs"""
610 if num_pos_only == 0:
611 return ()
612 has_kwargs = any(x.kind == x.VAR_KEYWORD
613 for x in sigspec.parameters.values())
614 if not has_kwargs:
615 return ()
616 pos_args = list(sigspec.parameters.values())[:num_pos_only]
617 return tuple(x.name for x in pos_args)
620def signature_or_spec(func):
621 try:
622 return inspect.signature(func)
623 except (ValueError, TypeError):
624 return None
627def expand_sig(sig):
628 """ Convert the signature spec in ``module_info`` to add to ``signatures``
630 The input signature spec is one of:
631 - ``lambda_func``
632 - ``(num_position_args, lambda_func)``
633 - ``(num_position_args, lambda_func, keyword_only_args)``
635 The output signature spec is:
636 ``(num_position_args, lambda_func, keyword_exclude, sigspec)``
638 where ``keyword_exclude`` includes keyword only arguments and, if variadic
639 keywords is present, the names of position-only argument. The latter is
640 included to support builtins such as ``partial(func, *args, **kwargs)``,
641 which allows ``func=`` to be used as a keyword even though it's the name
642 of a positional argument.
643 """
644 if isinstance(sig, tuple):
645 if len(sig) == 3:
646 num_pos_only, func, keyword_only = sig
647 assert isinstance(sig[-1], tuple)
648 else:
649 num_pos_only, func = sig
650 keyword_only = ()
651 sigspec = signature_or_spec(func)
652 else:
653 func = sig
654 sigspec = signature_or_spec(func)
655 num_pos_only = num_pos_args(sigspec)
656 keyword_only = ()
657 keyword_exclude = get_exclude_keywords(num_pos_only, sigspec)
658 return num_pos_only, func, keyword_only + keyword_exclude, sigspec
661signatures = {}
664def create_signature_registry(module_info=module_info, signatures=signatures):
665 for module, info in module_info.items():
666 if isinstance(module, str):
667 module = import_module(module)
668 for name, sigs in info.items():
669 if hasattr(module, name):
670 new_sigs = tuple(expand_sig(sig) for sig in sigs)
671 signatures[getattr(module, name)] = new_sigs
674def check_valid(sig, args, kwargs):
675 """ Like ``is_valid_args`` for the given signature spec"""
676 num_pos_only, func, keyword_exclude, sigspec = sig
677 if len(args) < num_pos_only:
678 return False
679 if keyword_exclude:
680 kwargs = dict(kwargs)
681 for item in keyword_exclude:
682 kwargs.pop(item, None)
683 try:
684 func(*args, **kwargs)
685 return True
686 except TypeError:
687 return False
690def _is_valid_args(func, args, kwargs):
691 """ Like ``is_valid_args`` for builtins in our ``signatures`` registry"""
692 if func not in signatures:
693 return None
694 sigs = signatures[func]
695 return any(check_valid(sig, args, kwargs) for sig in sigs)
698def check_partial(sig, args, kwargs):
699 """ Like ``is_partial_args`` for the given signature spec"""
700 num_pos_only, func, keyword_exclude, sigspec = sig
701 if len(args) < num_pos_only:
702 pad = (None,) * (num_pos_only - len(args))
703 args = args + pad
704 if keyword_exclude:
705 kwargs = dict(kwargs)
706 for item in keyword_exclude:
707 kwargs.pop(item, None)
708 return is_partial_args(func, args, kwargs, sigspec)
711def _is_partial_args(func, args, kwargs):
712 """ Like ``is_partial_args`` for builtins in our ``signatures`` registry"""
713 if func not in signatures:
714 return None
715 sigs = signatures[func]
716 return any(check_partial(sig, args, kwargs) for sig in sigs)
719def check_arity(n, sig):
720 num_pos_only, func, keyword_exclude, sigspec = sig
721 if keyword_exclude or num_pos_only > n:
722 return False
723 return is_arity(n, func, sigspec)
726def _is_arity(n, func):
727 if func not in signatures:
728 return None
729 sigs = signatures[func]
730 checks = [check_arity(n, sig) for sig in sigs]
731 if all(checks):
732 return True
733 elif any(checks):
734 return None
735 return False
738def check_varargs(sig):
739 num_pos_only, func, keyword_exclude, sigspec = sig
740 return has_varargs(func, sigspec)
743def _has_varargs(func):
744 if func not in signatures:
745 return None
746 sigs = signatures[func]
747 checks = [check_varargs(sig) for sig in sigs]
748 if all(checks):
749 return True
750 elif any(checks):
751 return None
752 return False
755def check_keywords(sig):
756 num_pos_only, func, keyword_exclude, sigspec = sig
757 if keyword_exclude:
758 return True
759 return has_keywords(func, sigspec)
762def _has_keywords(func):
763 if func not in signatures:
764 return None
765 sigs = signatures[func]
766 checks = [check_keywords(sig) for sig in sigs]
767 if all(checks):
768 return True
769 elif any(checks):
770 return None
771 return False
774def check_required_args(sig):
775 num_pos_only, func, keyword_exclude, sigspec = sig
776 return num_required_args(func, sigspec)
779def _num_required_args(func):
780 if func not in signatures:
781 return None
782 sigs = signatures[func]
783 vals = [check_required_args(sig) for sig in sigs]
784 val = vals[0]
785 if all(x == val for x in vals):
786 return val
787 return None