Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/wrapt/wrappers.py: 31%

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

462 statements  

1import inspect 

2import operator 

3import sys 

4 

5 

6def with_metaclass(meta, *bases): 

7 """Create a base class with a metaclass.""" 

8 return meta("NewBase", bases, {}) 

9 

10 

11class WrapperNotInitializedError(ValueError, AttributeError): 

12 """ 

13 Exception raised when a wrapper is accessed before it has been initialized. 

14 To satisfy different situations where this could arise, we inherit from both 

15 ValueError and AttributeError. 

16 """ 

17 

18 pass 

19 

20 

21class _ObjectProxyMethods: 

22 

23 # We use properties to override the values of __module__ and 

24 # __doc__. If we add these in ObjectProxy, the derived class 

25 # __dict__ will still be setup to have string variants of these 

26 # attributes and the rules of descriptors means that they appear to 

27 # take precedence over the properties in the base class. To avoid 

28 # that, we copy the properties into the derived class type itself 

29 # via a meta class. In that way the properties will always take 

30 # precedence. 

31 

32 @property 

33 def __module__(self): 

34 return self.__wrapped__.__module__ 

35 

36 @__module__.setter 

37 def __module__(self, value): 

38 self.__wrapped__.__module__ = value 

39 

40 @property 

41 def __doc__(self): 

42 return self.__wrapped__.__doc__ 

43 

44 @__doc__.setter 

45 def __doc__(self, value): 

46 self.__wrapped__.__doc__ = value 

47 

48 # We similar use a property for __dict__. We need __dict__ to be 

49 # explicit to ensure that vars() works as expected. 

50 

51 @property 

52 def __dict__(self): 

53 return self.__wrapped__.__dict__ 

54 

55 # Need to also propagate the special __weakref__ attribute for case 

56 # where decorating classes which will define this. If do not define 

57 # it and use a function like inspect.getmembers() on a decorator 

58 # class it will fail. This can't be in the derived classes. 

59 

60 @property 

61 def __weakref__(self): 

62 return self.__wrapped__.__weakref__ 

63 

64 

65class _ObjectProxyMetaType(type): 

66 def __new__(cls, name, bases, dictionary): 

67 # Copy our special properties into the class so that they 

68 # always take precedence over attributes of the same name added 

69 # during construction of a derived class. This is to save 

70 # duplicating the implementation for them in all derived classes. 

71 

72 dictionary.update(vars(_ObjectProxyMethods)) 

73 

74 return type.__new__(cls, name, bases, dictionary) 

75 

76 

77# NOTE: Although Python 3+ supports the newer metaclass=MetaClass syntax, 

78# we must continue using with_metaclass() for ObjectProxy. The newer syntax 

79# changes how __slots__ is handled during class creation, which would break 

80# the ability to set _self_* attributes on ObjectProxy instances. The 

81# with_metaclass() approach creates an intermediate base class that allows 

82# the necessary attribute flexibility while still applying the metaclass. 

83 

84 

85class ObjectProxy(with_metaclass(_ObjectProxyMetaType)): # type: ignore[misc] 

86 

87 __slots__ = "__wrapped__" 

88 

89 def __init__(self, wrapped): 

90 """Create an object proxy around the given object.""" 

91 

92 if wrapped is None: 

93 try: 

94 callback = object.__getattribute__(self, "__wrapped_factory__") 

95 except AttributeError: 

96 callback = None 

97 

98 if callback is not None: 

99 # If wrapped is none and class has a __wrapped_factory__ 

100 # method, then we don't set __wrapped__ yet and instead will 

101 # defer creation of the wrapped object until it is first 

102 # needed. 

103 

104 pass 

105 

106 else: 

107 object.__setattr__(self, "__wrapped__", wrapped) 

108 else: 

109 object.__setattr__(self, "__wrapped__", wrapped) 

110 

111 # Python 3.2+ has the __qualname__ attribute, but it does not 

112 # allow it to be overridden using a property and it must instead 

113 # be an actual string object instead. 

114 

115 try: 

116 object.__setattr__(self, "__qualname__", wrapped.__qualname__) 

117 except AttributeError: 

118 pass 

119 

120 # Python 3.10 onwards also does not allow itself to be overridden 

121 # using a property and it must instead be set explicitly. 

122 

123 try: 

124 object.__setattr__(self, "__annotations__", wrapped.__annotations__) 

125 except AttributeError: 

126 pass 

127 

128 @property 

129 def __object_proxy__(self): 

130 return ObjectProxy 

131 

132 def __self_setattr__(self, name, value): 

133 object.__setattr__(self, name, value) 

134 

135 @property 

136 def __name__(self): 

137 return self.__wrapped__.__name__ 

138 

139 @__name__.setter 

140 def __name__(self, value): 

141 self.__wrapped__.__name__ = value 

142 

143 @property 

144 def __class__(self): 

145 return self.__wrapped__.__class__ 

146 

147 @__class__.setter 

148 def __class__(self, value): 

149 self.__wrapped__.__class__ = value 

150 

151 def __dir__(self): 

152 return dir(self.__wrapped__) 

153 

154 def __str__(self): 

155 return str(self.__wrapped__) 

156 

157 def __bytes__(self): 

158 return bytes(self.__wrapped__) 

159 

160 def __repr__(self): 

161 return f"<{type(self).__name__} at 0x{id(self):x} for {type(self.__wrapped__).__name__} at 0x{id(self.__wrapped__):x}>" 

162 

163 def __format__(self, format_spec): 

164 return format(self.__wrapped__, format_spec) 

165 

166 def __reversed__(self): 

167 return reversed(self.__wrapped__) 

168 

169 def __round__(self, ndigits=None): 

170 return round(self.__wrapped__, ndigits) 

171 

172 def __mro_entries__(self, bases): 

173 if not isinstance(self.__wrapped__, type) and hasattr( 

174 self.__wrapped__, "__mro_entries__" 

175 ): 

176 return self.__wrapped__.__mro_entries__(bases) 

177 return (self.__wrapped__,) 

178 

179 def __lt__(self, other): 

180 return self.__wrapped__ < other 

181 

182 def __le__(self, other): 

183 return self.__wrapped__ <= other 

184 

185 def __eq__(self, other): 

186 return self.__wrapped__ == other 

187 

188 def __ne__(self, other): 

189 return self.__wrapped__ != other 

190 

191 def __gt__(self, other): 

192 return self.__wrapped__ > other 

193 

194 def __ge__(self, other): 

195 return self.__wrapped__ >= other 

196 

197 def __hash__(self): 

198 return hash(self.__wrapped__) 

199 

200 def __nonzero__(self): 

201 return bool(self.__wrapped__) 

202 

203 def __bool__(self): 

204 return bool(self.__wrapped__) 

205 

206 def __setattr__(self, name, value): 

207 if name.startswith("_self_"): 

208 object.__setattr__(self, name, value) 

209 

210 elif name == "__wrapped__": 

211 object.__setattr__(self, name, value) 

212 

213 try: 

214 object.__delattr__(self, "__qualname__") 

215 except AttributeError: 

216 pass 

217 try: 

218 object.__setattr__(self, "__qualname__", value.__qualname__) 

219 except AttributeError: 

220 pass 

221 try: 

222 object.__delattr__(self, "__annotations__") 

223 except AttributeError: 

224 pass 

225 try: 

226 object.__setattr__(self, "__annotations__", value.__annotations__) 

227 except AttributeError: 

228 pass 

229 

230 __wrapped_setattr_fixups__ = getattr( 

231 self, "__wrapped_setattr_fixups__", None 

232 ) 

233 

234 if __wrapped_setattr_fixups__ is not None: 

235 __wrapped_setattr_fixups__() 

236 

237 elif name == "__qualname__": 

238 setattr(self.__wrapped__, name, value) 

239 object.__setattr__(self, name, value) 

240 

241 elif name == "__annotations__": 

242 setattr(self.__wrapped__, name, value) 

243 object.__setattr__(self, name, value) 

244 

245 elif hasattr(type(self), name): 

246 object.__setattr__(self, name, value) 

247 

248 else: 

249 setattr(self.__wrapped__, name, value) 

250 

251 def __getattr__(self, name): 

252 # If we need to lookup `__wrapped__` then the `__init__()` method 

253 # cannot have been called, or this is a lazy object proxy which is 

254 # deferring creation of the wrapped object until it is first needed. 

255 

256 if name == "__wrapped__": 

257 # Note that we use existance of `__wrapped_factory__` to gate whether 

258 # we can attempt to initialize the wrapped object lazily, but it is 

259 # `__wrapped_get__` that we actually call to do the initialization. 

260 # This is so that we can handle multithreading correctly by having 

261 # `__wrapped_get__` use a lock to protect against multiple threads 

262 # trying to initialize the wrapped object at the same time. 

263 

264 try: 

265 object.__getattribute__(self, "__wrapped_factory__") 

266 except AttributeError: 

267 pass 

268 else: 

269 return object.__getattribute__(self, "__wrapped_get__")() 

270 

271 raise WrapperNotInitializedError("wrapper has not been initialized") 

272 

273 return getattr(self.__wrapped__, name) 

274 

275 def __delattr__(self, name): 

276 if name.startswith("_self_"): 

277 object.__delattr__(self, name) 

278 

279 elif name == "__wrapped__": 

280 raise TypeError("__wrapped__ attribute cannot be deleted") 

281 

282 elif name == "__qualname__": 

283 object.__delattr__(self, name) 

284 delattr(self.__wrapped__, name) 

285 

286 elif name == "__annotations__": 

287 object.__delattr__(self, name) 

288 delattr(self.__wrapped__, name) 

289 

290 elif hasattr(type(self), name): 

291 object.__delattr__(self, name) 

292 

293 else: 

294 delattr(self.__wrapped__, name) 

295 

296 def __add__(self, other): 

297 return self.__wrapped__ + other 

298 

299 def __sub__(self, other): 

300 return self.__wrapped__ - other 

301 

302 def __mul__(self, other): 

303 return self.__wrapped__ * other 

304 

305 def __truediv__(self, other): 

306 return operator.truediv(self.__wrapped__, other) 

307 

308 def __floordiv__(self, other): 

309 return self.__wrapped__ // other 

310 

311 def __mod__(self, other): 

312 return self.__wrapped__ % other 

313 

314 def __divmod__(self, other): 

315 return divmod(self.__wrapped__, other) 

316 

317 def __pow__(self, other, *args): 

318 return pow(self.__wrapped__, other, *args) 

319 

320 def __lshift__(self, other): 

321 return self.__wrapped__ << other 

322 

323 def __rshift__(self, other): 

324 return self.__wrapped__ >> other 

325 

326 def __and__(self, other): 

327 return self.__wrapped__ & other 

328 

329 def __xor__(self, other): 

330 return self.__wrapped__ ^ other 

331 

332 def __or__(self, other): 

333 return self.__wrapped__ | other 

334 

335 def __radd__(self, other): 

336 return other + self.__wrapped__ 

337 

338 def __rsub__(self, other): 

339 return other - self.__wrapped__ 

340 

341 def __rmul__(self, other): 

342 return other * self.__wrapped__ 

343 

344 def __rtruediv__(self, other): 

345 return operator.truediv(other, self.__wrapped__) 

346 

347 def __rfloordiv__(self, other): 

348 return other // self.__wrapped__ 

349 

350 def __rmod__(self, other): 

351 return other % self.__wrapped__ 

352 

353 def __rdivmod__(self, other): 

354 return divmod(other, self.__wrapped__) 

355 

356 def __rpow__(self, other, *args): 

357 return pow(other, self.__wrapped__, *args) 

358 

359 def __rlshift__(self, other): 

360 return other << self.__wrapped__ 

361 

362 def __rrshift__(self, other): 

363 return other >> self.__wrapped__ 

364 

365 def __rand__(self, other): 

366 return other & self.__wrapped__ 

367 

368 def __rxor__(self, other): 

369 return other ^ self.__wrapped__ 

370 

371 def __ror__(self, other): 

372 return other | self.__wrapped__ 

373 

374 def __iadd__(self, other): 

375 if hasattr(self.__wrapped__, "__iadd__"): 

376 self.__wrapped__ += other 

377 return self 

378 else: 

379 return self.__object_proxy__(self.__wrapped__ + other) 

380 

381 def __isub__(self, other): 

382 if hasattr(self.__wrapped__, "__isub__"): 

383 self.__wrapped__ -= other 

384 return self 

385 else: 

386 return self.__object_proxy__(self.__wrapped__ - other) 

387 

388 def __imul__(self, other): 

389 if hasattr(self.__wrapped__, "__imul__"): 

390 self.__wrapped__ *= other 

391 return self 

392 else: 

393 return self.__object_proxy__(self.__wrapped__ * other) 

394 

395 def __itruediv__(self, other): 

396 if hasattr(self.__wrapped__, "__itruediv__"): 

397 self.__wrapped__ /= other 

398 return self 

399 else: 

400 return self.__object_proxy__(self.__wrapped__ / other) 

401 

402 def __ifloordiv__(self, other): 

403 if hasattr(self.__wrapped__, "__ifloordiv__"): 

404 self.__wrapped__ //= other 

405 return self 

406 else: 

407 return self.__object_proxy__(self.__wrapped__ // other) 

408 

409 def __imod__(self, other): 

410 if hasattr(self.__wrapped__, "__imod__"): 

411 self.__wrapped__ %= other 

412 return self 

413 else: 

414 return self.__object_proxy__(self.__wrapped__ % other) 

415 

416 return self 

417 

418 def __ipow__(self, other): # type: ignore[misc] 

419 if hasattr(self.__wrapped__, "__ipow__"): 

420 self.__wrapped__ **= other 

421 return self 

422 else: 

423 return self.__object_proxy__(self.__wrapped__**other) 

424 

425 def __ilshift__(self, other): 

426 if hasattr(self.__wrapped__, "__ilshift__"): 

427 self.__wrapped__ <<= other 

428 return self 

429 else: 

430 return self.__object_proxy__(self.__wrapped__ << other) 

431 

432 def __irshift__(self, other): 

433 if hasattr(self.__wrapped__, "__irshift__"): 

434 self.__wrapped__ >>= other 

435 return self 

436 else: 

437 return self.__object_proxy__(self.__wrapped__ >> other) 

438 

439 def __iand__(self, other): 

440 if hasattr(self.__wrapped__, "__iand__"): 

441 self.__wrapped__ &= other 

442 return self 

443 else: 

444 return self.__object_proxy__(self.__wrapped__ & other) 

445 

446 def __ixor__(self, other): 

447 if hasattr(self.__wrapped__, "__ixor__"): 

448 self.__wrapped__ ^= other 

449 return self 

450 else: 

451 return self.__object_proxy__(self.__wrapped__ ^ other) 

452 

453 def __ior__(self, other): 

454 if hasattr(self.__wrapped__, "__ior__"): 

455 self.__wrapped__ |= other 

456 return self 

457 else: 

458 return self.__object_proxy__(self.__wrapped__ | other) 

459 

460 def __neg__(self): 

461 return -self.__wrapped__ 

462 

463 def __pos__(self): 

464 return +self.__wrapped__ 

465 

466 def __abs__(self): 

467 return abs(self.__wrapped__) 

468 

469 def __invert__(self): 

470 return ~self.__wrapped__ 

471 

472 def __int__(self): 

473 return int(self.__wrapped__) 

474 

475 def __float__(self): 

476 return float(self.__wrapped__) 

477 

478 def __complex__(self): 

479 return complex(self.__wrapped__) 

480 

481 def __oct__(self): 

482 return oct(self.__wrapped__) 

483 

484 def __hex__(self): 

485 return hex(self.__wrapped__) 

486 

487 def __index__(self): 

488 return operator.index(self.__wrapped__) 

489 

490 def __matmul__(self, other): 

491 return self.__wrapped__ @ other 

492 

493 def __rmatmul__(self, other): 

494 return other @ self.__wrapped__ 

495 

496 def __imatmul__(self, other): 

497 if hasattr(self.__wrapped__, "__imatmul__"): 

498 self.__wrapped__ @= other 

499 return self 

500 else: 

501 return self.__object_proxy__(self.__wrapped__ @ other) 

502 

503 def __len__(self): 

504 return len(self.__wrapped__) 

505 

506 def __contains__(self, value): 

507 return value in self.__wrapped__ 

508 

509 def __getitem__(self, key): 

510 return self.__wrapped__[key] 

511 

512 def __setitem__(self, key, value): 

513 self.__wrapped__[key] = value 

514 

515 def __delitem__(self, key): 

516 del self.__wrapped__[key] 

517 

518 def __getslice__(self, i, j): 

519 return self.__wrapped__[i:j] 

520 

521 def __setslice__(self, i, j, value): 

522 self.__wrapped__[i:j] = value 

523 

524 def __delslice__(self, i, j): 

525 del self.__wrapped__[i:j] 

526 

527 def __enter__(self): 

528 return self.__wrapped__.__enter__() 

529 

530 def __exit__(self, *args, **kwargs): 

531 return self.__wrapped__.__exit__(*args, **kwargs) 

532 

533 def __aenter__(self): 

534 return self.__wrapped__.__aenter__() 

535 

536 def __aexit__(self, *args, **kwargs): 

537 return self.__wrapped__.__aexit__(*args, **kwargs) 

538 

539 def __copy__(self): 

540 raise NotImplementedError("object proxy must define __copy__()") 

541 

542 def __deepcopy__(self, memo): 

543 raise NotImplementedError("object proxy must define __deepcopy__()") 

544 

545 def __reduce__(self): 

546 raise NotImplementedError("object proxy must define __reduce__()") 

547 

548 def __reduce_ex__(self, protocol): 

549 raise NotImplementedError("object proxy must define __reduce_ex__()") 

550 

551 

552class CallableObjectProxy(ObjectProxy): 

553 

554 def __call__(*args, **kwargs): 

555 def _unpack_self(self, *args): 

556 return self, args 

557 

558 self, args = _unpack_self(*args) 

559 

560 return self.__wrapped__(*args, **kwargs) 

561 

562 

563class PartialCallableObjectProxy(ObjectProxy): 

564 """A callable object proxy that supports partial application of arguments 

565 and keywords. 

566 """ 

567 

568 def __init__(*args, **kwargs): 

569 """Create a callable object proxy with partial application of the given 

570 arguments and keywords. This behaves the same as `functools.partial`, but 

571 implemented using the `ObjectProxy` class to provide better support for 

572 introspection. 

573 """ 

574 

575 def _unpack_self(self, *args): 

576 return self, args 

577 

578 self, args = _unpack_self(*args) 

579 

580 if len(args) < 1: 

581 raise TypeError("partial type takes at least one argument") 

582 

583 wrapped, args = args[0], args[1:] 

584 

585 if not callable(wrapped): 

586 raise TypeError("the first argument must be callable") 

587 

588 super(PartialCallableObjectProxy, self).__init__(wrapped) 

589 

590 self._self_args = args 

591 self._self_kwargs = kwargs 

592 

593 def __call__(*args, **kwargs): 

594 def _unpack_self(self, *args): 

595 return self, args 

596 

597 self, args = _unpack_self(*args) 

598 

599 _args = self._self_args + args 

600 

601 _kwargs = dict(self._self_kwargs) 

602 _kwargs.update(kwargs) 

603 

604 return self.__wrapped__(*_args, **_kwargs) 

605 

606 

607class _FunctionWrapperBase(ObjectProxy): 

608 

609 __slots__ = ( 

610 "_self_instance", 

611 "_self_wrapper", 

612 "_self_enabled", 

613 "_self_binding", 

614 "_self_parent", 

615 "_self_owner", 

616 ) 

617 

618 def __init__( 

619 self, 

620 wrapped, 

621 instance, 

622 wrapper, 

623 enabled=None, 

624 binding="callable", 

625 parent=None, 

626 owner=None, 

627 ): 

628 

629 super(_FunctionWrapperBase, self).__init__(wrapped) 

630 

631 object.__setattr__(self, "_self_instance", instance) 

632 object.__setattr__(self, "_self_wrapper", wrapper) 

633 object.__setattr__(self, "_self_enabled", enabled) 

634 object.__setattr__(self, "_self_binding", binding) 

635 object.__setattr__(self, "_self_parent", parent) 

636 object.__setattr__(self, "_self_owner", owner) 

637 

638 def __get__(self, instance, owner): 

639 # This method is actually doing double duty for both unbound and bound 

640 # derived wrapper classes. It should possibly be broken up and the 

641 # distinct functionality moved into the derived classes. Can't do that 

642 # straight away due to some legacy code which is relying on it being 

643 # here in this base class. 

644 # 

645 # The distinguishing attribute which determines whether we are being 

646 # called in an unbound or bound wrapper is the parent attribute. If 

647 # binding has never occurred, then the parent will be None. 

648 # 

649 # First therefore, is if we are called in an unbound wrapper. In this 

650 # case we perform the binding. 

651 # 

652 # We have two special cases to worry about here. These are where we are 

653 # decorating a class or builtin function as neither provide a __get__() 

654 # method to call. In this case we simply return self. 

655 # 

656 # Note that we otherwise still do binding even if instance is None and 

657 # accessing an unbound instance method from a class. This is because we 

658 # need to be able to later detect that specific case as we will need to 

659 # extract the instance from the first argument of those passed in. 

660 

661 if self._self_parent is None: 

662 # Technically can probably just check for existence of __get__ on 

663 # the wrapped object, but this is more explicit. 

664 

665 if self._self_binding == "builtin": 

666 return self 

667 

668 if self._self_binding == "class": 

669 return self 

670 

671 binder = getattr(self.__wrapped__, "__get__", None) 

672 

673 if binder is None: 

674 return self 

675 

676 descriptor = binder(instance, owner) 

677 

678 return self.__bound_function_wrapper__( 

679 descriptor, 

680 instance, 

681 self._self_wrapper, 

682 self._self_enabled, 

683 self._self_binding, 

684 self, 

685 owner, 

686 ) 

687 

688 # Now we have the case of binding occurring a second time on what was 

689 # already a bound function. In this case we would usually return 

690 # ourselves again. This mirrors what Python does. 

691 # 

692 # The special case this time is where we were originally bound with an 

693 # instance of None and we were likely an instance method. In that case 

694 # we rebind against the original wrapped function from the parent again. 

695 

696 if self._self_instance is None and self._self_binding in ( 

697 "function", 

698 "instancemethod", 

699 "callable", 

700 ): 

701 descriptor = self._self_parent.__wrapped__.__get__(instance, owner) 

702 

703 return self._self_parent.__bound_function_wrapper__( 

704 descriptor, 

705 instance, 

706 self._self_wrapper, 

707 self._self_enabled, 

708 self._self_binding, 

709 self._self_parent, 

710 owner, 

711 ) 

712 

713 return self 

714 

715 def __call__(*args, **kwargs): 

716 def _unpack_self(self, *args): 

717 return self, args 

718 

719 self, args = _unpack_self(*args) 

720 

721 # If enabled has been specified, then evaluate it at this point 

722 # and if the wrapper is not to be executed, then simply return 

723 # the bound function rather than a bound wrapper for the bound 

724 # function. When evaluating enabled, if it is callable we call 

725 # it, otherwise we evaluate it as a boolean. 

726 

727 if self._self_enabled is not None: 

728 if callable(self._self_enabled): 

729 if not self._self_enabled(): 

730 return self.__wrapped__(*args, **kwargs) 

731 elif not self._self_enabled: 

732 return self.__wrapped__(*args, **kwargs) 

733 

734 # This can occur where initial function wrapper was applied to 

735 # a function that was already bound to an instance. In that case 

736 # we want to extract the instance from the function and use it. 

737 

738 if self._self_binding in ( 

739 "function", 

740 "instancemethod", 

741 "classmethod", 

742 "callable", 

743 ): 

744 if self._self_instance is None: 

745 instance = getattr(self.__wrapped__, "__self__", None) 

746 if instance is not None: 

747 return self._self_wrapper(self.__wrapped__, instance, args, kwargs) 

748 

749 # This is generally invoked when the wrapped function is being 

750 # called as a normal function and is not bound to a class as an 

751 # instance method. This is also invoked in the case where the 

752 # wrapped function was a method, but this wrapper was in turn 

753 # wrapped using the staticmethod decorator. 

754 

755 return self._self_wrapper(self.__wrapped__, self._self_instance, args, kwargs) 

756 

757 def __set_name__(self, owner, name): 

758 # This is a special method use to supply information to 

759 # descriptors about what the name of variable in a class 

760 # definition is. Not wanting to add this to ObjectProxy as not 

761 # sure of broader implications of doing that. Thus restrict to 

762 # FunctionWrapper used by decorators. 

763 

764 if hasattr(self.__wrapped__, "__set_name__"): 

765 self.__wrapped__.__set_name__(owner, name) 

766 

767 def __instancecheck__(self, instance): 

768 # This is a special method used by isinstance() to make checks 

769 # instance of the `__wrapped__`. 

770 return isinstance(instance, self.__wrapped__) 

771 

772 def __subclasscheck__(self, subclass): 

773 # This is a special method used by issubclass() to make checks 

774 # about inheritance of classes. We need to upwrap any object 

775 # proxy. Not wanting to add this to ObjectProxy as not sure of 

776 # broader implications of doing that. Thus restrict to 

777 # FunctionWrapper used by decorators. 

778 

779 if hasattr(subclass, "__wrapped__"): 

780 return issubclass(subclass.__wrapped__, self.__wrapped__) 

781 else: 

782 return issubclass(subclass, self.__wrapped__) 

783 

784 

785class BoundFunctionWrapper(_FunctionWrapperBase): 

786 

787 def __call__(*args, **kwargs): 

788 def _unpack_self(self, *args): 

789 return self, args 

790 

791 self, args = _unpack_self(*args) 

792 

793 # If enabled has been specified, then evaluate it at this point and if 

794 # the wrapper is not to be executed, then simply return the bound 

795 # function rather than a bound wrapper for the bound function. When 

796 # evaluating enabled, if it is callable we call it, otherwise we 

797 # evaluate it as a boolean. 

798 

799 if self._self_enabled is not None: 

800 if callable(self._self_enabled): 

801 if not self._self_enabled(): 

802 return self.__wrapped__(*args, **kwargs) 

803 elif not self._self_enabled: 

804 return self.__wrapped__(*args, **kwargs) 

805 

806 # We need to do things different depending on whether we are likely 

807 # wrapping an instance method vs a static method or class method. 

808 

809 if self._self_binding == "function": 

810 if self._self_instance is None and args: 

811 instance, newargs = args[0], args[1:] 

812 if isinstance(instance, self._self_owner): 

813 wrapped = PartialCallableObjectProxy(self.__wrapped__, instance) 

814 return self._self_wrapper(wrapped, instance, newargs, kwargs) 

815 

816 return self._self_wrapper( 

817 self.__wrapped__, self._self_instance, args, kwargs 

818 ) 

819 

820 elif self._self_binding == "callable": 

821 if self._self_instance is None: 

822 # This situation can occur where someone is calling the 

823 # instancemethod via the class type and passing the instance as 

824 # the first argument. We need to shift the args before making 

825 # the call to the wrapper and effectively bind the instance to 

826 # the wrapped function using a partial so the wrapper doesn't 

827 # see anything as being different. 

828 

829 if not args: 

830 raise TypeError("missing 1 required positional argument") 

831 

832 instance, args = args[0], args[1:] 

833 wrapped = PartialCallableObjectProxy(self.__wrapped__, instance) 

834 return self._self_wrapper(wrapped, instance, args, kwargs) 

835 

836 return self._self_wrapper( 

837 self.__wrapped__, self._self_instance, args, kwargs 

838 ) 

839 

840 else: 

841 # As in this case we would be dealing with a classmethod or 

842 # staticmethod, then _self_instance will only tell us whether 

843 # when calling the classmethod or staticmethod they did it via an 

844 # instance of the class it is bound to and not the case where 

845 # done by the class type itself. We thus ignore _self_instance 

846 # and use the __self__ attribute of the bound function instead. 

847 # For a classmethod, this means instance will be the class type 

848 # and for a staticmethod it will be None. This is probably the 

849 # more useful thing we can pass through even though we loose 

850 # knowledge of whether they were called on the instance vs the 

851 # class type, as it reflects what they have available in the 

852 # decoratored function. 

853 

854 instance = getattr(self.__wrapped__, "__self__", None) 

855 

856 return self._self_wrapper(self.__wrapped__, instance, args, kwargs) 

857 

858 

859class FunctionWrapper(_FunctionWrapperBase): 

860 """ 

861 A wrapper for callable objects that can be used to apply decorators to 

862 functions, methods, classmethods, and staticmethods, or any other callable. 

863 It handles binding and unbinding of methods, and allows for the wrapper to 

864 be enabled or disabled. 

865 """ 

866 

867 __bound_function_wrapper__ = BoundFunctionWrapper 

868 

869 def __init__(self, wrapped, wrapper, enabled=None): 

870 """ 

871 Initialize the `FunctionWrapper` with the `wrapped` callable, the 

872 `wrapper` function, and an optional `enabled` argument. The `enabled` 

873 argument can be a boolean or a callable that returns a boolean. When a 

874 callable is provided, it will be called each time the wrapper is 

875 invoked to determine if the wrapper function should be executed or 

876 whether the wrapped function should be called directly. If `enabled` 

877 is not provided, the wrapper is enabled by default. 

878 """ 

879 

880 # What it is we are wrapping here could be anything. We need to 

881 # try and detect specific cases though. In particular, we need 

882 # to detect when we are given something that is a method of a 

883 # class. Further, we need to know when it is likely an instance 

884 # method, as opposed to a class or static method. This can 

885 # become problematic though as there isn't strictly a fool proof 

886 # method of knowing. 

887 # 

888 # The situations we could encounter when wrapping a method are: 

889 # 

890 # 1. The wrapper is being applied as part of a decorator which 

891 # is a part of the class definition. In this case what we are 

892 # given is the raw unbound function, classmethod or staticmethod 

893 # wrapper objects. 

894 # 

895 # The problem here is that we will not know we are being applied 

896 # in the context of the class being set up. This becomes 

897 # important later for the case of an instance method, because in 

898 # that case we just see it as a raw function and can't 

899 # distinguish it from wrapping a normal function outside of 

900 # a class context. 

901 # 

902 # 2. The wrapper is being applied when performing monkey 

903 # patching of the class type afterwards and the method to be 

904 # wrapped was retrieved direct from the __dict__ of the class 

905 # type. This is effectively the same as (1) above. 

906 # 

907 # 3. The wrapper is being applied when performing monkey 

908 # patching of the class type afterwards and the method to be 

909 # wrapped was retrieved from the class type. In this case 

910 # binding will have been performed where the instance against 

911 # which the method is bound will be None at that point. 

912 # 

913 # This case is a problem because we can no longer tell if the 

914 # method was a static method, plus if using Python3, we cannot 

915 # tell if it was an instance method as the concept of an 

916 # unnbound method no longer exists. 

917 # 

918 # 4. The wrapper is being applied when performing monkey 

919 # patching of an instance of a class. In this case binding will 

920 # have been performed where the instance was not None. 

921 # 

922 # This case is a problem because we can no longer tell if the 

923 # method was a static method. 

924 # 

925 # Overall, the best we can do is look at the original type of the 

926 # object which was wrapped prior to any binding being done and 

927 # see if it is an instance of classmethod or staticmethod. In 

928 # the case where other decorators are between us and them, if 

929 # they do not propagate the __class__ attribute so that the 

930 # isinstance() checks works, then likely this will do the wrong 

931 # thing where classmethod and staticmethod are used. 

932 # 

933 # Since it is likely to be very rare that anyone even puts 

934 # decorators around classmethod and staticmethod, likelihood of 

935 # that being an issue is very small, so we accept it and suggest 

936 # that those other decorators be fixed. It is also only an issue 

937 # if a decorator wants to actually do things with the arguments. 

938 # 

939 # As to not being able to identify static methods properly, we 

940 # just hope that that isn't something people are going to want 

941 # to wrap, or if they do suggest they do it the correct way by 

942 # ensuring that it is decorated in the class definition itself, 

943 # or patch it in the __dict__ of the class type. 

944 # 

945 # So to get the best outcome we can, whenever we aren't sure what 

946 # it is, we label it as a 'callable'. If it was already bound and 

947 # that is rebound later, we assume that it will be an instance 

948 # method and try and cope with the possibility that the 'self' 

949 # argument it being passed as an explicit argument and shuffle 

950 # the arguments around to extract 'self' for use as the instance. 

951 

952 binding = None 

953 

954 if isinstance(wrapped, _FunctionWrapperBase): 

955 binding = wrapped._self_binding 

956 

957 if not binding: 

958 if inspect.isbuiltin(wrapped): 

959 binding = "builtin" 

960 

961 elif inspect.isfunction(wrapped): 

962 binding = "function" 

963 

964 elif inspect.isclass(wrapped): 

965 binding = "class" 

966 

967 elif isinstance(wrapped, classmethod): 

968 binding = "classmethod" 

969 

970 elif isinstance(wrapped, staticmethod): 

971 binding = "staticmethod" 

972 

973 elif hasattr(wrapped, "__self__"): 

974 if inspect.isclass(wrapped.__self__): 

975 binding = "classmethod" 

976 elif inspect.ismethod(wrapped): 

977 binding = "instancemethod" 

978 else: 

979 binding = "callable" 

980 

981 else: 

982 binding = "callable" 

983 

984 super(FunctionWrapper, self).__init__(wrapped, None, wrapper, enabled, binding)