Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/toolz/functoolz.py: 30%

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

412 statements  

1from functools import reduce, partial 

2import inspect 

3import sys 

4from operator import attrgetter, not_ 

5from importlib import import_module 

6from types import MethodType 

7 

8from .utils import no_default 

9 

10PYPY = hasattr(sys, 'pypy_version_info') and sys.version_info[0] > 2 

11 

12 

13__all__ = ('identity', 'apply', 'thread_first', 'thread_last', 'memoize', 

14 'compose', 'compose_left', 'pipe', 'complement', 'juxt', 'do', 

15 'curry', 'flip', 'excepts') 

16 

17PYPY = hasattr(sys, 'pypy_version_info') 

18 

19 

20def identity(x): 

21 """ Identity function. Return x 

22 

23 >>> identity(3) 

24 3 

25 """ 

26 return x 

27 

28 

29def apply(*func_and_args, **kwargs): 

30 """ Applies a function and returns the results 

31 

32 >>> def double(x): return 2*x 

33 >>> def inc(x): return x + 1 

34 >>> apply(double, 5) 

35 10 

36 

37 >>> tuple(map(apply, [double, inc, double], [10, 500, 8000])) 

38 (20, 501, 16000) 

39 """ 

40 if not func_and_args: 

41 raise TypeError('func argument is required') 

42 func, args = func_and_args[0], func_and_args[1:] 

43 return func(*args, **kwargs) 

44 

45 

46def thread_first(val, *forms): 

47 """ Thread value through a sequence of functions/forms 

48 

49 >>> def double(x): return 2*x 

50 >>> def inc(x): return x + 1 

51 >>> thread_first(1, inc, double) 

52 4 

53 

54 If the function expects more than one input you can specify those inputs 

55 in a tuple. The value is used as the first input. 

56 

57 >>> def add(x, y): return x + y 

58 >>> def pow(x, y): return x**y 

59 >>> thread_first(1, (add, 4), (pow, 2)) # pow(add(1, 4), 2) 

60 25 

61 

62 So in general 

63 thread_first(x, f, (g, y, z)) 

64 expands to 

65 g(f(x), y, z) 

66 

67 See Also: 

68 thread_last 

69 """ 

70 def evalform_front(val, form): 

71 if callable(form): 

72 return form(val) 

73 if isinstance(form, tuple): 

74 func, args = form[0], form[1:] 

75 args = (val,) + args 

76 return func(*args) 

77 return reduce(evalform_front, forms, val) 

78 

79 

80def thread_last(val, *forms): 

81 """ Thread value through a sequence of functions/forms 

82 

83 >>> def double(x): return 2*x 

84 >>> def inc(x): return x + 1 

85 >>> thread_last(1, inc, double) 

86 4 

87 

88 If the function expects more than one input you can specify those inputs 

89 in a tuple. The value is used as the last input. 

90 

91 >>> def add(x, y): return x + y 

92 >>> def pow(x, y): return x**y 

93 >>> thread_last(1, (add, 4), (pow, 2)) # pow(2, add(4, 1)) 

94 32 

95 

96 So in general 

97 thread_last(x, f, (g, y, z)) 

98 expands to 

99 g(y, z, f(x)) 

100 

101 >>> def iseven(x): 

102 ... return x % 2 == 0 

103 >>> list(thread_last([1, 2, 3], (map, inc), (filter, iseven))) 

104 [2, 4] 

105 

106 See Also: 

107 thread_first 

108 """ 

109 def evalform_back(val, form): 

110 if callable(form): 

111 return form(val) 

112 if isinstance(form, tuple): 

113 func, args = form[0], form[1:] 

114 args = args + (val,) 

115 return func(*args) 

116 return reduce(evalform_back, forms, val) 

117 

118 

119def instanceproperty(fget=None, fset=None, fdel=None, doc=None, classval=None): 

120 """ Like @property, but returns ``classval`` when used as a class attribute 

121 

122 >>> class MyClass(object): 

123 ... '''The class docstring''' 

124 ... @instanceproperty(classval=__doc__) 

125 ... def __doc__(self): 

126 ... return 'An object docstring' 

127 ... @instanceproperty 

128 ... def val(self): 

129 ... return 42 

130 ... 

131 >>> MyClass.__doc__ 

132 'The class docstring' 

133 >>> MyClass.val is None 

134 True 

135 >>> obj = MyClass() 

136 >>> obj.__doc__ 

137 'An object docstring' 

138 >>> obj.val 

139 42 

140 """ 

141 if fget is None: 

142 return partial(instanceproperty, fset=fset, fdel=fdel, doc=doc, 

143 classval=classval) 

144 return InstanceProperty(fget=fget, fset=fset, fdel=fdel, doc=doc, 

145 classval=classval) 

146 

147 

148class InstanceProperty(property): 

149 """ Like @property, but returns ``classval`` when used as a class attribute 

150 

151 Should not be used directly. Use ``instanceproperty`` instead. 

152 """ 

153 def __init__(self, fget=None, fset=None, fdel=None, doc=None, 

154 classval=None): 

155 self.classval = classval 

156 property.__init__(self, fget=fget, fset=fset, fdel=fdel, doc=doc) 

157 

158 def __get__(self, obj, type=None): 

159 if obj is None: 

160 return self.classval 

161 return property.__get__(self, obj, type) 

162 

163 def __reduce__(self): 

164 state = (self.fget, self.fset, self.fdel, self.__doc__, self.classval) 

165 return InstanceProperty, state 

166 

167 

168class curry(object): 

169 """ Curry a callable function 

170 

171 Enables partial application of arguments through calling a function with an 

172 incomplete set of arguments. 

173 

174 >>> def mul(x, y): 

175 ... return x * y 

176 >>> mul = curry(mul) 

177 

178 >>> double = mul(2) 

179 >>> double(10) 

180 20 

181 

182 Also supports keyword arguments 

183 

184 >>> @curry # Can use curry as a decorator 

185 ... def f(x, y, a=10): 

186 ... return a * (x + y) 

187 

188 >>> add = f(a=1) 

189 >>> add(2, 3) 

190 5 

191 

192 See Also: 

193 toolz.curried - namespace of curried functions 

194 https://toolz.readthedocs.io/en/latest/curry.html 

195 """ 

196 def __init__(self, *args, **kwargs): 

197 if not args: 

198 raise TypeError('__init__() takes at least 2 arguments (1 given)') 

199 func, args = args[0], args[1:] 

200 if not callable(func): 

201 raise TypeError("Input must be callable") 

202 

203 # curry- or functools.partial-like object? Unpack and merge arguments 

204 if ( 

205 hasattr(func, 'func') 

206 and hasattr(func, 'args') 

207 and hasattr(func, 'keywords') 

208 and isinstance(func.args, tuple) 

209 ): 

210 _kwargs = {} 

211 if func.keywords: 

212 _kwargs.update(func.keywords) 

213 _kwargs.update(kwargs) 

214 kwargs = _kwargs 

215 args = func.args + args 

216 func = func.func 

217 

218 if kwargs: 

219 self._partial = partial(func, *args, **kwargs) 

220 else: 

221 self._partial = partial(func, *args) 

222 

223 self.__doc__ = getattr(func, '__doc__', None) 

224 self.__name__ = getattr(func, '__name__', '<curry>') 

225 self.__module__ = getattr(func, '__module__', None) 

226 self.__qualname__ = getattr(func, '__qualname__', None) 

227 self._sigspec = None 

228 self._has_unknown_args = None 

229 

230 @instanceproperty 

231 def func(self): 

232 return self._partial.func 

233 

234 @instanceproperty 

235 def __signature__(self): 

236 sig = inspect.signature(self.func) 

237 args = self.args or () 

238 keywords = self.keywords or {} 

239 if is_partial_args(self.func, args, keywords, sig) is False: 

240 raise TypeError('curry object has incorrect arguments') 

241 

242 params = list(sig.parameters.values()) 

243 skip = 0 

244 for param in params[:len(args)]: 

245 if param.kind == param.VAR_POSITIONAL: 

246 break 

247 skip += 1 

248 

249 kwonly = False 

250 newparams = [] 

251 for param in params[skip:]: 

252 kind = param.kind 

253 default = param.default 

254 if kind == param.VAR_KEYWORD: 

255 pass 

256 elif kind == param.VAR_POSITIONAL: 

257 if kwonly: 

258 continue 

259 elif param.name in keywords: 

260 default = keywords[param.name] 

261 kind = param.KEYWORD_ONLY 

262 kwonly = True 

263 else: 

264 if kwonly: 

265 kind = param.KEYWORD_ONLY 

266 if default is param.empty: 

267 default = no_default 

268 newparams.append(param.replace(default=default, kind=kind)) 

269 

270 return sig.replace(parameters=newparams) 

271 

272 @instanceproperty 

273 def args(self): 

274 return self._partial.args 

275 

276 @instanceproperty 

277 def keywords(self): 

278 return self._partial.keywords 

279 

280 @instanceproperty 

281 def func_name(self): 

282 return self.__name__ 

283 

284 def __str__(self): 

285 return str(self.func) 

286 

287 def __repr__(self): 

288 return repr(self.func) 

289 

290 def __hash__(self): 

291 return hash((self.func, self.args, 

292 frozenset(self.keywords.items()) if self.keywords 

293 else None)) 

294 

295 def __eq__(self, other): 

296 return (isinstance(other, curry) and self.func == other.func and 

297 self.args == other.args and self.keywords == other.keywords) 

298 

299 def __ne__(self, other): 

300 return not self.__eq__(other) 

301 

302 def __call__(self, *args, **kwargs): 

303 try: 

304 return self._partial(*args, **kwargs) 

305 except TypeError as exc: 

306 if self._should_curry(args, kwargs, exc): 

307 return self.bind(*args, **kwargs) 

308 raise 

309 

310 def _should_curry(self, args, kwargs, exc=None): 

311 func = self.func 

312 args = self.args + args 

313 if self.keywords: 

314 kwargs = dict(self.keywords, **kwargs) 

315 if self._sigspec is None: 

316 sigspec = self._sigspec = _sigs.signature_or_spec(func) 

317 self._has_unknown_args = has_varargs(func, sigspec) is not False 

318 else: 

319 sigspec = self._sigspec 

320 

321 if is_partial_args(func, args, kwargs, sigspec) is False: 

322 # Nothing can make the call valid 

323 return False 

324 elif self._has_unknown_args: 

325 # The call may be valid and raised a TypeError, but we curry 

326 # anyway because the function may have `*args`. This is useful 

327 # for decorators with signature `func(*args, **kwargs)`. 

328 return True 

329 elif not is_valid_args(func, args, kwargs, sigspec): 

330 # Adding more arguments may make the call valid 

331 return True 

332 else: 

333 # There was a genuine TypeError 

334 return False 

335 

336 def bind(self, *args, **kwargs): 

337 return type(self)(self, *args, **kwargs) 

338 

339 def call(self, *args, **kwargs): 

340 return self._partial(*args, **kwargs) 

341 

342 def __get__(self, instance, owner): 

343 if instance is None: 

344 return self 

345 return curry(self, instance) 

346 

347 def __reduce__(self): 

348 func = self.func 

349 modname = getattr(func, '__module__', None) 

350 qualname = getattr(func, '__qualname__', None) 

351 if qualname is None: # pragma: no cover 

352 qualname = getattr(func, '__name__', None) 

353 is_decorated = None 

354 if modname and qualname: 

355 attrs = [] 

356 obj = import_module(modname) 

357 for attr in qualname.split('.'): 

358 if isinstance(obj, curry): 

359 attrs.append('func') 

360 obj = obj.func 

361 obj = getattr(obj, attr, None) 

362 if obj is None: 

363 break 

364 attrs.append(attr) 

365 if isinstance(obj, curry) and obj.func is func: 

366 is_decorated = obj is self 

367 qualname = '.'.join(attrs) 

368 func = '%s:%s' % (modname, qualname) 

369 

370 # functools.partial objects can't be pickled 

371 userdict = tuple((k, v) for k, v in self.__dict__.items() 

372 if k not in ('_partial', '_sigspec')) 

373 state = (type(self), func, self.args, self.keywords, userdict, 

374 is_decorated) 

375 return _restore_curry, state 

376 

377 

378def _restore_curry(cls, func, args, kwargs, userdict, is_decorated): 

379 if isinstance(func, str): 

380 modname, qualname = func.rsplit(':', 1) 

381 obj = import_module(modname) 

382 for attr in qualname.split('.'): 

383 obj = getattr(obj, attr) 

384 if is_decorated: 

385 return obj 

386 func = obj.func 

387 obj = cls(func, *args, **(kwargs or {})) 

388 obj.__dict__.update(userdict) 

389 return obj 

390 

391 

392@curry 

393def memoize(func, cache=None, key=None): 

394 """ Cache a function's result for speedy future evaluation 

395 

396 Considerations: 

397 Trades memory for speed. 

398 Only use on pure functions. 

399 

400 >>> def add(x, y): return x + y 

401 >>> add = memoize(add) 

402 

403 Or use as a decorator 

404 

405 >>> @memoize 

406 ... def add(x, y): 

407 ... return x + y 

408 

409 Use the ``cache`` keyword to provide a dict-like object as an initial cache 

410 

411 >>> @memoize(cache={(1, 2): 3}) 

412 ... def add(x, y): 

413 ... return x + y 

414 

415 Note that the above works as a decorator because ``memoize`` is curried. 

416 

417 It is also possible to provide a ``key(args, kwargs)`` function that 

418 calculates keys used for the cache, which receives an ``args`` tuple and 

419 ``kwargs`` dict as input, and must return a hashable value. However, 

420 the default key function should be sufficient most of the time. 

421 

422 >>> # Use key function that ignores extraneous keyword arguments 

423 >>> @memoize(key=lambda args, kwargs: args) 

424 ... def add(x, y, verbose=False): 

425 ... if verbose: 

426 ... print('Calculating %s + %s' % (x, y)) 

427 ... return x + y 

428 """ 

429 if cache is None: 

430 cache = {} 

431 

432 try: 

433 may_have_kwargs = has_keywords(func) is not False 

434 # Is unary function (single arg, no variadic argument or keywords)? 

435 is_unary = is_arity(1, func) 

436 except TypeError: # pragma: no cover 

437 may_have_kwargs = True 

438 is_unary = False 

439 

440 if key is None: 

441 if is_unary: 

442 def key(args, kwargs): 

443 return args[0] 

444 elif may_have_kwargs: 

445 def key(args, kwargs): 

446 return ( 

447 args or None, 

448 frozenset(kwargs.items()) if kwargs else None, 

449 ) 

450 else: 

451 def key(args, kwargs): 

452 return args 

453 

454 def memof(*args, **kwargs): 

455 k = key(args, kwargs) 

456 try: 

457 return cache[k] 

458 except TypeError: 

459 raise TypeError("Arguments to memoized function must be hashable") 

460 except KeyError: 

461 cache[k] = result = func(*args, **kwargs) 

462 return result 

463 

464 try: 

465 memof.__name__ = func.__name__ 

466 except AttributeError: 

467 pass 

468 memof.__doc__ = func.__doc__ 

469 memof.__wrapped__ = func 

470 return memof 

471 

472 

473class Compose(object): 

474 """ A composition of functions 

475 

476 See Also: 

477 compose 

478 """ 

479 __slots__ = 'first', 'funcs' 

480 

481 def __init__(self, funcs): 

482 funcs = tuple(reversed(funcs)) 

483 self.first = funcs[0] 

484 self.funcs = funcs[1:] 

485 

486 def __call__(self, *args, **kwargs): 

487 ret = self.first(*args, **kwargs) 

488 for f in self.funcs: 

489 ret = f(ret) 

490 return ret 

491 

492 def __getstate__(self): 

493 return self.first, self.funcs 

494 

495 def __setstate__(self, state): 

496 self.first, self.funcs = state 

497 

498 @instanceproperty(classval=__doc__) 

499 def __doc__(self): 

500 def composed_doc(*fs): 

501 """Generate a docstring for the composition of fs. 

502 """ 

503 if not fs: 

504 # Argument name for the docstring. 

505 return '*args, **kwargs' 

506 

507 return '{f}({g})'.format(f=fs[0].__name__, g=composed_doc(*fs[1:])) 

508 

509 try: 

510 return ( 

511 'lambda *args, **kwargs: ' + 

512 composed_doc(*reversed((self.first,) + self.funcs)) 

513 ) 

514 except AttributeError: 

515 # One of our callables does not have a `__name__`, whatever. 

516 return 'A composition of functions' 

517 

518 @property 

519 def __name__(self): 

520 try: 

521 return '_of_'.join( 

522 (f.__name__ for f in reversed((self.first,) + self.funcs)) 

523 ) 

524 except AttributeError: 

525 return type(self).__name__ 

526 

527 def __repr__(self): 

528 return '{.__class__.__name__}{!r}'.format( 

529 self, tuple(reversed((self.first, ) + self.funcs))) 

530 

531 def __eq__(self, other): 

532 if isinstance(other, Compose): 

533 return other.first == self.first and other.funcs == self.funcs 

534 return NotImplemented 

535 

536 def __ne__(self, other): 

537 equality = self.__eq__(other) 

538 return NotImplemented if equality is NotImplemented else not equality 

539 

540 def __hash__(self): 

541 return hash(self.first) ^ hash(self.funcs) 

542 

543 # Mimic the descriptor behavior of python functions. 

544 # i.e. let Compose be called as a method when bound to a class. 

545 # adapted from 

546 # docs.python.org/3/howto/descriptor.html#functions-and-methods 

547 def __get__(self, obj, objtype=None): 

548 return self if obj is None else MethodType(self, obj) 

549 

550 # introspection with Signature is only possible from py3.3+ 

551 @instanceproperty 

552 def __signature__(self): 

553 base = inspect.signature(self.first) 

554 last = inspect.signature(self.funcs[-1]) 

555 return base.replace(return_annotation=last.return_annotation) 

556 

557 __wrapped__ = instanceproperty(attrgetter('first')) 

558 

559 

560def compose(*funcs): 

561 """ Compose functions to operate in series. 

562 

563 Returns a function that applies other functions in sequence. 

564 

565 Functions are applied from right to left so that 

566 ``compose(f, g, h)(x, y)`` is the same as ``f(g(h(x, y)))``. 

567 

568 If no arguments are provided, the identity function (f(x) = x) is returned. 

569 

570 >>> inc = lambda i: i + 1 

571 >>> compose(str, inc)(3) 

572 '4' 

573 

574 See Also: 

575 compose_left 

576 pipe 

577 """ 

578 if not funcs: 

579 return identity 

580 if len(funcs) == 1: 

581 return funcs[0] 

582 else: 

583 return Compose(funcs) 

584 

585 

586def compose_left(*funcs): 

587 """ Compose functions to operate in series. 

588 

589 Returns a function that applies other functions in sequence. 

590 

591 Functions are applied from left to right so that 

592 ``compose_left(f, g, h)(x, y)`` is the same as ``h(g(f(x, y)))``. 

593 

594 If no arguments are provided, the identity function (f(x) = x) is returned. 

595 

596 >>> inc = lambda i: i + 1 

597 >>> compose_left(inc, str)(3) 

598 '4' 

599 

600 See Also: 

601 compose 

602 pipe 

603 """ 

604 return compose(*reversed(funcs)) 

605 

606 

607def pipe(data, *funcs): 

608 """ Pipe a value through a sequence of functions 

609 

610 I.e. ``pipe(data, f, g, h)`` is equivalent to ``h(g(f(data)))`` 

611 

612 We think of the value as progressing through a pipe of several 

613 transformations, much like pipes in UNIX 

614 

615 ``$ cat data | f | g | h`` 

616 

617 >>> double = lambda i: 2 * i 

618 >>> pipe(3, double, str) 

619 '6' 

620 

621 See Also: 

622 compose 

623 compose_left 

624 thread_first 

625 thread_last 

626 """ 

627 for func in funcs: 

628 data = func(data) 

629 return data 

630 

631 

632def complement(func): 

633 """ Convert a predicate function to its logical complement. 

634 

635 In other words, return a function that, for inputs that normally 

636 yield True, yields False, and vice-versa. 

637 

638 >>> def iseven(n): return n % 2 == 0 

639 >>> isodd = complement(iseven) 

640 >>> iseven(2) 

641 True 

642 >>> isodd(2) 

643 False 

644 """ 

645 return compose(not_, func) 

646 

647 

648class juxt(object): 

649 """ Creates a function that calls several functions with the same arguments 

650 

651 Takes several functions and returns a function that applies its arguments 

652 to each of those functions then returns a tuple of the results. 

653 

654 Name comes from juxtaposition: the fact of two things being seen or placed 

655 close together with contrasting effect. 

656 

657 >>> inc = lambda x: x + 1 

658 >>> double = lambda x: x * 2 

659 >>> juxt(inc, double)(10) 

660 (11, 20) 

661 >>> juxt([inc, double])(10) 

662 (11, 20) 

663 """ 

664 __slots__ = ['funcs'] 

665 

666 def __init__(self, *funcs): 

667 if len(funcs) == 1 and not callable(funcs[0]): 

668 funcs = funcs[0] 

669 self.funcs = tuple(funcs) 

670 

671 def __call__(self, *args, **kwargs): 

672 return tuple(func(*args, **kwargs) for func in self.funcs) 

673 

674 def __getstate__(self): 

675 return self.funcs 

676 

677 def __setstate__(self, state): 

678 self.funcs = state 

679 

680 

681def do(func, x): 

682 """ Runs ``func`` on ``x``, returns ``x`` 

683 

684 Because the results of ``func`` are not returned, only the side 

685 effects of ``func`` are relevant. 

686 

687 Logging functions can be made by composing ``do`` with a storage function 

688 like ``list.append`` or ``file.write`` 

689 

690 >>> from toolz import compose 

691 >>> from toolz.curried import do 

692 

693 >>> log = [] 

694 >>> inc = lambda x: x + 1 

695 >>> inc = compose(inc, do(log.append)) 

696 >>> inc(1) 

697 2 

698 >>> inc(11) 

699 12 

700 >>> log 

701 [1, 11] 

702 """ 

703 func(x) 

704 return x 

705 

706 

707@curry 

708def flip(func, a, b): 

709 """ Call the function call with the arguments flipped 

710 

711 This function is curried. 

712 

713 >>> def div(a, b): 

714 ... return a // b 

715 ... 

716 >>> flip(div, 2, 6) 

717 3 

718 >>> div_by_two = flip(div, 2) 

719 >>> div_by_two(4) 

720 2 

721 

722 This is particularly useful for built in functions and functions defined 

723 in C extensions that accept positional only arguments. For example: 

724 isinstance, issubclass. 

725 

726 >>> data = [1, 'a', 'b', 2, 1.5, object(), 3] 

727 >>> only_ints = list(filter(flip(isinstance, int), data)) 

728 >>> only_ints 

729 [1, 2, 3] 

730 """ 

731 return func(b, a) 

732 

733 

734def return_none(exc): 

735 """ Returns None. 

736 """ 

737 return None 

738 

739 

740class excepts(object): 

741 """A wrapper around a function to catch exceptions and 

742 dispatch to a handler. 

743 

744 This is like a functional try/except block, in the same way that 

745 ifexprs are functional if/else blocks. 

746 

747 Examples 

748 -------- 

749 >>> excepting = excepts( 

750 ... ValueError, 

751 ... lambda a: [1, 2].index(a), 

752 ... lambda _: -1, 

753 ... ) 

754 >>> excepting(1) 

755 0 

756 >>> excepting(3) 

757 -1 

758 

759 Multiple exceptions and default except clause. 

760 

761 >>> excepting = excepts((IndexError, KeyError), lambda a: a[0]) 

762 >>> excepting([]) 

763 >>> excepting([1]) 

764 1 

765 >>> excepting({}) 

766 >>> excepting({0: 1}) 

767 1 

768 """ 

769 def __init__(self, exc, func, handler=return_none): 

770 self.exc = exc 

771 self.func = func 

772 self.handler = handler 

773 

774 def __call__(self, *args, **kwargs): 

775 try: 

776 return self.func(*args, **kwargs) 

777 except self.exc as e: 

778 return self.handler(e) 

779 

780 @instanceproperty(classval=__doc__) 

781 def __doc__(self): 

782 from textwrap import dedent 

783 

784 exc = self.exc 

785 try: 

786 if isinstance(exc, tuple): 

787 exc_name = '(%s)' % ', '.join( 

788 map(attrgetter('__name__'), exc), 

789 ) 

790 else: 

791 exc_name = exc.__name__ 

792 

793 return dedent( 

794 """\ 

795 A wrapper around {inst.func.__name__!r} that will except: 

796 {exc} 

797 and handle any exceptions with {inst.handler.__name__!r}. 

798 

799 Docs for {inst.func.__name__!r}: 

800 {inst.func.__doc__} 

801 

802 Docs for {inst.handler.__name__!r}: 

803 {inst.handler.__doc__} 

804 """ 

805 ).format( 

806 inst=self, 

807 exc=exc_name, 

808 ) 

809 except AttributeError: 

810 return type(self).__doc__ 

811 

812 @property 

813 def __name__(self): 

814 exc = self.exc 

815 try: 

816 if isinstance(exc, tuple): 

817 exc_name = '_or_'.join(map(attrgetter('__name__'), exc)) 

818 else: 

819 exc_name = exc.__name__ 

820 return '%s_excepting_%s' % (self.func.__name__, exc_name) 

821 except AttributeError: 

822 return 'excepting' 

823 

824 

825def _check_sigspec(sigspec, func, builtin_func, *builtin_args): 

826 if sigspec is None: 

827 try: 

828 sigspec = inspect.signature(func) 

829 except (ValueError, TypeError) as e: 

830 sigspec = e 

831 if isinstance(sigspec, ValueError): 

832 return None, builtin_func(*builtin_args) 

833 elif not isinstance(sigspec, inspect.Signature): 

834 if ( 

835 func in _sigs.signatures 

836 and (( 

837 hasattr(func, '__signature__') 

838 and hasattr(func.__signature__, '__get__') 

839 )) 

840 ): 

841 val = builtin_func(*builtin_args) 

842 return None, val 

843 return None, False 

844 return sigspec, None 

845 

846 

847if PYPY: # pragma: no cover 

848 _check_sigspec_orig = _check_sigspec 

849 

850 def _check_sigspec(sigspec, func, builtin_func, *builtin_args): 

851 # PyPy may lie, so use our registry for builtins instead 

852 if func in _sigs.signatures: 

853 val = builtin_func(*builtin_args) 

854 return None, val 

855 return _check_sigspec_orig(sigspec, func, builtin_func, *builtin_args) 

856 

857 

858_check_sigspec.__doc__ = """ \ 

859Private function to aid in introspection compatibly across Python versions. 

860 

861If a callable doesn't have a signature (Python 3) or an argspec (Python 2), 

862the signature registry in toolz._signatures is used. 

863""" 

864 

865 

866def num_required_args(func, sigspec=None): 

867 sigspec, rv = _check_sigspec(sigspec, func, _sigs._num_required_args, 

868 func) 

869 if sigspec is None: 

870 return rv 

871 return sum(1 for p in sigspec.parameters.values() 

872 if p.default is p.empty 

873 and p.kind in (p.POSITIONAL_OR_KEYWORD, p.POSITIONAL_ONLY)) 

874 

875 

876def has_varargs(func, sigspec=None): 

877 sigspec, rv = _check_sigspec(sigspec, func, _sigs._has_varargs, func) 

878 if sigspec is None: 

879 return rv 

880 return any(p.kind == p.VAR_POSITIONAL 

881 for p in sigspec.parameters.values()) 

882 

883 

884def has_keywords(func, sigspec=None): 

885 sigspec, rv = _check_sigspec(sigspec, func, _sigs._has_keywords, func) 

886 if sigspec is None: 

887 return rv 

888 return any(p.default is not p.empty 

889 or p.kind in (p.KEYWORD_ONLY, p.VAR_KEYWORD) 

890 for p in sigspec.parameters.values()) 

891 

892 

893def is_valid_args(func, args, kwargs, sigspec=None): 

894 sigspec, rv = _check_sigspec(sigspec, func, _sigs._is_valid_args, 

895 func, args, kwargs) 

896 if sigspec is None: 

897 return rv 

898 try: 

899 sigspec.bind(*args, **kwargs) 

900 except TypeError: 

901 return False 

902 return True 

903 

904 

905def is_partial_args(func, args, kwargs, sigspec=None): 

906 sigspec, rv = _check_sigspec(sigspec, func, _sigs._is_partial_args, 

907 func, args, kwargs) 

908 if sigspec is None: 

909 return rv 

910 try: 

911 sigspec.bind_partial(*args, **kwargs) 

912 except TypeError: 

913 return False 

914 return True 

915 

916 

917def is_arity(n, func, sigspec=None): 

918 """ Does a function have only n positional arguments? 

919 

920 This function relies on introspection and does not call the function. 

921 Returns None if validity can't be determined. 

922 

923 >>> def f(x): 

924 ... return x 

925 >>> is_arity(1, f) 

926 True 

927 >>> def g(x, y=1): 

928 ... return x + y 

929 >>> is_arity(1, g) 

930 False 

931 """ 

932 sigspec, rv = _check_sigspec(sigspec, func, _sigs._is_arity, n, func) 

933 if sigspec is None: 

934 return rv 

935 num = num_required_args(func, sigspec) 

936 if num is not None: 

937 num = num == n 

938 if not num: 

939 return False 

940 varargs = has_varargs(func, sigspec) 

941 if varargs: 

942 return False 

943 keywords = has_keywords(func, sigspec) 

944 if keywords: 

945 return False 

946 if num is None or varargs is None or keywords is None: # pragma: no cover 

947 return None 

948 return True 

949 

950 

951num_required_args.__doc__ = """ \ 

952Number of required positional arguments 

953 

954 This function relies on introspection and does not call the function. 

955 Returns None if validity can't be determined. 

956 

957 >>> def f(x, y, z=3): 

958 ... return x + y + z 

959 >>> num_required_args(f) 

960 2 

961 >>> def g(*args, **kwargs): 

962 ... pass 

963 >>> num_required_args(g) 

964 0 

965 """ 

966 

967has_varargs.__doc__ = """ \ 

968Does a function have variadic positional arguments? 

969 

970 This function relies on introspection and does not call the function. 

971 Returns None if validity can't be determined. 

972 

973 >>> def f(*args): 

974 ... return args 

975 >>> has_varargs(f) 

976 True 

977 >>> def g(**kwargs): 

978 ... return kwargs 

979 >>> has_varargs(g) 

980 False 

981 """ 

982 

983has_keywords.__doc__ = """ \ 

984Does a function have keyword arguments? 

985 

986 This function relies on introspection and does not call the function. 

987 Returns None if validity can't be determined. 

988 

989 >>> def f(x, y=0): 

990 ... return x + y 

991 

992 >>> has_keywords(f) 

993 True 

994 """ 

995 

996is_valid_args.__doc__ = """ \ 

997Is ``func(*args, **kwargs)`` a valid function call? 

998 

999 This function relies on introspection and does not call the function. 

1000 Returns None if validity can't be determined. 

1001 

1002 >>> def add(x, y): 

1003 ... return x + y 

1004 

1005 >>> is_valid_args(add, (1,), {}) 

1006 False 

1007 >>> is_valid_args(add, (1, 2), {}) 

1008 True 

1009 >>> is_valid_args(map, (), {}) 

1010 False 

1011 

1012 **Implementation notes** 

1013 Python 2 relies on ``inspect.getargspec``, which only works for 

1014 user-defined functions. Python 3 uses ``inspect.signature``, which 

1015 works for many more types of callables. 

1016 

1017 Many builtins in the standard library are also supported. 

1018 """ 

1019 

1020is_partial_args.__doc__ = """ \ 

1021Can partial(func, *args, **kwargs)(*args2, **kwargs2) be a valid call? 

1022 

1023 Returns True *only* if the call is valid or if it is possible for the 

1024 call to become valid by adding more positional or keyword arguments. 

1025 

1026 This function relies on introspection and does not call the function. 

1027 Returns None if validity can't be determined. 

1028 

1029 >>> def add(x, y): 

1030 ... return x + y 

1031 

1032 >>> is_partial_args(add, (1,), {}) 

1033 True 

1034 >>> is_partial_args(add, (1, 2), {}) 

1035 True 

1036 >>> is_partial_args(add, (1, 2, 3), {}) 

1037 False 

1038 >>> is_partial_args(map, (), {}) 

1039 True 

1040 

1041 **Implementation notes** 

1042 Python 2 relies on ``inspect.getargspec``, which only works for 

1043 user-defined functions. Python 3 uses ``inspect.signature``, which 

1044 works for many more types of callables. 

1045 

1046 Many builtins in the standard library are also supported. 

1047 """ 

1048 

1049from . import _signatures as _sigs