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

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

417 statements  

1import sys 

2import operator 

3import inspect 

4 

5PY2 = sys.version_info[0] == 2 

6 

7if PY2: 

8 string_types = basestring, 

9else: 

10 string_types = str, 

11 

12def with_metaclass(meta, *bases): 

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

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

15 

16class _ObjectProxyMethods(object): 

17 

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

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

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

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

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

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

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

25 # precedence. 

26 

27 @property 

28 def __module__(self): 

29 return self.__wrapped__.__module__ 

30 

31 @__module__.setter 

32 def __module__(self, value): 

33 self.__wrapped__.__module__ = value 

34 

35 @property 

36 def __doc__(self): 

37 return self.__wrapped__.__doc__ 

38 

39 @__doc__.setter 

40 def __doc__(self, value): 

41 self.__wrapped__.__doc__ = value 

42 

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

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

45 

46 @property 

47 def __dict__(self): 

48 return self.__wrapped__.__dict__ 

49 

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

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

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

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

54 

55 @property 

56 def __weakref__(self): 

57 return self.__wrapped__.__weakref__ 

58 

59class _ObjectProxyMetaType(type): 

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

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

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

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

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

65 

66 dictionary.update(vars(_ObjectProxyMethods)) 

67 

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

69 

70class ObjectProxy(with_metaclass(_ObjectProxyMetaType)): 

71 

72 __slots__ = '__wrapped__' 

73 

74 def __init__(self, wrapped): 

75 object.__setattr__(self, '__wrapped__', wrapped) 

76 

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

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

79 # be an actual string object instead. 

80 

81 try: 

82 object.__setattr__(self, '__qualname__', wrapped.__qualname__) 

83 except AttributeError: 

84 pass 

85 

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

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

88 

89 try: 

90 object.__setattr__(self, '__annotations__', wrapped.__annotations__) 

91 except AttributeError: 

92 pass 

93 

94 def __self_setattr__(self, name, value): 

95 object.__setattr__(self, name, value) 

96 

97 @property 

98 def __name__(self): 

99 return self.__wrapped__.__name__ 

100 

101 @__name__.setter 

102 def __name__(self, value): 

103 self.__wrapped__.__name__ = value 

104 

105 @property 

106 def __class__(self): 

107 return self.__wrapped__.__class__ 

108 

109 @__class__.setter 

110 def __class__(self, value): 

111 self.__wrapped__.__class__ = value 

112 

113 def __dir__(self): 

114 return dir(self.__wrapped__) 

115 

116 def __str__(self): 

117 return str(self.__wrapped__) 

118 

119 if not PY2: 

120 def __bytes__(self): 

121 return bytes(self.__wrapped__) 

122 

123 def __repr__(self): 

124 return '<{} at 0x{:x} for {} at 0x{:x}>'.format( 

125 type(self).__name__, id(self), 

126 type(self.__wrapped__).__name__, 

127 id(self.__wrapped__)) 

128 

129 def __format__(self, format_spec): 

130 return format(self.__wrapped__, format_spec) 

131 

132 def __reversed__(self): 

133 return reversed(self.__wrapped__) 

134 

135 if not PY2: 

136 def __round__(self, ndigits=None): 

137 return round(self.__wrapped__, ndigits) 

138 

139 if sys.hexversion >= 0x03070000: 

140 def __mro_entries__(self, bases): 

141 return (self.__wrapped__,) 

142 

143 def __lt__(self, other): 

144 return self.__wrapped__ < other 

145 

146 def __le__(self, other): 

147 return self.__wrapped__ <= other 

148 

149 def __eq__(self, other): 

150 return self.__wrapped__ == other 

151 

152 def __ne__(self, other): 

153 return self.__wrapped__ != other 

154 

155 def __gt__(self, other): 

156 return self.__wrapped__ > other 

157 

158 def __ge__(self, other): 

159 return self.__wrapped__ >= other 

160 

161 def __hash__(self): 

162 return hash(self.__wrapped__) 

163 

164 def __nonzero__(self): 

165 return bool(self.__wrapped__) 

166 

167 def __bool__(self): 

168 return bool(self.__wrapped__) 

169 

170 def __setattr__(self, name, value): 

171 if name.startswith('_self_'): 

172 object.__setattr__(self, name, value) 

173 

174 elif name == '__wrapped__': 

175 object.__setattr__(self, name, value) 

176 try: 

177 object.__delattr__(self, '__qualname__') 

178 except AttributeError: 

179 pass 

180 try: 

181 object.__setattr__(self, '__qualname__', value.__qualname__) 

182 except AttributeError: 

183 pass 

184 try: 

185 object.__delattr__(self, '__annotations__') 

186 except AttributeError: 

187 pass 

188 try: 

189 object.__setattr__(self, '__annotations__', value.__annotations__) 

190 except AttributeError: 

191 pass 

192 

193 elif name == '__qualname__': 

194 setattr(self.__wrapped__, name, value) 

195 object.__setattr__(self, name, value) 

196 

197 elif name == '__annotations__': 

198 setattr(self.__wrapped__, name, value) 

199 object.__setattr__(self, name, value) 

200 

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

202 object.__setattr__(self, name, value) 

203 

204 else: 

205 setattr(self.__wrapped__, name, value) 

206 

207 def __getattr__(self, name): 

208 # If we are being to lookup '__wrapped__' then the 

209 # '__init__()' method cannot have been called. 

210 

211 if name == '__wrapped__': 

212 raise ValueError('wrapper has not been initialised') 

213 

214 return getattr(self.__wrapped__, name) 

215 

216 def __delattr__(self, name): 

217 if name.startswith('_self_'): 

218 object.__delattr__(self, name) 

219 

220 elif name == '__wrapped__': 

221 raise TypeError('__wrapped__ must be an object') 

222 

223 elif name == '__qualname__': 

224 object.__delattr__(self, name) 

225 delattr(self.__wrapped__, name) 

226 

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

228 object.__delattr__(self, name) 

229 

230 else: 

231 delattr(self.__wrapped__, name) 

232 

233 def __add__(self, other): 

234 return self.__wrapped__ + other 

235 

236 def __sub__(self, other): 

237 return self.__wrapped__ - other 

238 

239 def __mul__(self, other): 

240 return self.__wrapped__ * other 

241 

242 def __div__(self, other): 

243 return operator.div(self.__wrapped__, other) 

244 

245 def __truediv__(self, other): 

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

247 

248 def __floordiv__(self, other): 

249 return self.__wrapped__ // other 

250 

251 def __mod__(self, other): 

252 return self.__wrapped__ % other 

253 

254 def __divmod__(self, other): 

255 return divmod(self.__wrapped__, other) 

256 

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

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

259 

260 def __lshift__(self, other): 

261 return self.__wrapped__ << other 

262 

263 def __rshift__(self, other): 

264 return self.__wrapped__ >> other 

265 

266 def __and__(self, other): 

267 return self.__wrapped__ & other 

268 

269 def __xor__(self, other): 

270 return self.__wrapped__ ^ other 

271 

272 def __or__(self, other): 

273 return self.__wrapped__ | other 

274 

275 def __radd__(self, other): 

276 return other + self.__wrapped__ 

277 

278 def __rsub__(self, other): 

279 return other - self.__wrapped__ 

280 

281 def __rmul__(self, other): 

282 return other * self.__wrapped__ 

283 

284 def __rdiv__(self, other): 

285 return operator.div(other, self.__wrapped__) 

286 

287 def __rtruediv__(self, other): 

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

289 

290 def __rfloordiv__(self, other): 

291 return other // self.__wrapped__ 

292 

293 def __rmod__(self, other): 

294 return other % self.__wrapped__ 

295 

296 def __rdivmod__(self, other): 

297 return divmod(other, self.__wrapped__) 

298 

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

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

301 

302 def __rlshift__(self, other): 

303 return other << self.__wrapped__ 

304 

305 def __rrshift__(self, other): 

306 return other >> self.__wrapped__ 

307 

308 def __rand__(self, other): 

309 return other & self.__wrapped__ 

310 

311 def __rxor__(self, other): 

312 return other ^ self.__wrapped__ 

313 

314 def __ror__(self, other): 

315 return other | self.__wrapped__ 

316 

317 def __iadd__(self, other): 

318 self.__wrapped__ += other 

319 return self 

320 

321 def __isub__(self, other): 

322 self.__wrapped__ -= other 

323 return self 

324 

325 def __imul__(self, other): 

326 self.__wrapped__ *= other 

327 return self 

328 

329 def __idiv__(self, other): 

330 self.__wrapped__ = operator.idiv(self.__wrapped__, other) 

331 return self 

332 

333 def __itruediv__(self, other): 

334 self.__wrapped__ = operator.itruediv(self.__wrapped__, other) 

335 return self 

336 

337 def __ifloordiv__(self, other): 

338 self.__wrapped__ //= other 

339 return self 

340 

341 def __imod__(self, other): 

342 self.__wrapped__ %= other 

343 return self 

344 

345 def __ipow__(self, other): 

346 self.__wrapped__ **= other 

347 return self 

348 

349 def __ilshift__(self, other): 

350 self.__wrapped__ <<= other 

351 return self 

352 

353 def __irshift__(self, other): 

354 self.__wrapped__ >>= other 

355 return self 

356 

357 def __iand__(self, other): 

358 self.__wrapped__ &= other 

359 return self 

360 

361 def __ixor__(self, other): 

362 self.__wrapped__ ^= other 

363 return self 

364 

365 def __ior__(self, other): 

366 self.__wrapped__ |= other 

367 return self 

368 

369 def __neg__(self): 

370 return -self.__wrapped__ 

371 

372 def __pos__(self): 

373 return +self.__wrapped__ 

374 

375 def __abs__(self): 

376 return abs(self.__wrapped__) 

377 

378 def __invert__(self): 

379 return ~self.__wrapped__ 

380 

381 def __int__(self): 

382 return int(self.__wrapped__) 

383 

384 def __long__(self): 

385 return long(self.__wrapped__) 

386 

387 def __float__(self): 

388 return float(self.__wrapped__) 

389 

390 def __complex__(self): 

391 return complex(self.__wrapped__) 

392 

393 def __oct__(self): 

394 return oct(self.__wrapped__) 

395 

396 def __hex__(self): 

397 return hex(self.__wrapped__) 

398 

399 def __index__(self): 

400 return operator.index(self.__wrapped__) 

401 

402 def __len__(self): 

403 return len(self.__wrapped__) 

404 

405 def __contains__(self, value): 

406 return value in self.__wrapped__ 

407 

408 def __getitem__(self, key): 

409 return self.__wrapped__[key] 

410 

411 def __setitem__(self, key, value): 

412 self.__wrapped__[key] = value 

413 

414 def __delitem__(self, key): 

415 del self.__wrapped__[key] 

416 

417 def __getslice__(self, i, j): 

418 return self.__wrapped__[i:j] 

419 

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

421 self.__wrapped__[i:j] = value 

422 

423 def __delslice__(self, i, j): 

424 del self.__wrapped__[i:j] 

425 

426 def __enter__(self): 

427 return self.__wrapped__.__enter__() 

428 

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

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

431 

432 def __iter__(self): 

433 return iter(self.__wrapped__) 

434 

435 def __copy__(self): 

436 raise NotImplementedError('object proxy must define __copy__()') 

437 

438 def __deepcopy__(self, memo): 

439 raise NotImplementedError('object proxy must define __deepcopy__()') 

440 

441 def __reduce__(self): 

442 raise NotImplementedError( 

443 'object proxy must define __reduce__()') 

444 

445 def __reduce_ex__(self, protocol): 

446 raise NotImplementedError( 

447 'object proxy must define __reduce_ex__()') 

448 

449class CallableObjectProxy(ObjectProxy): 

450 

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

452 def _unpack_self(self, *args): 

453 return self, args 

454 

455 self, args = _unpack_self(*args) 

456 

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

458 

459class PartialCallableObjectProxy(ObjectProxy): 

460 

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

462 def _unpack_self(self, *args): 

463 return self, args 

464 

465 self, args = _unpack_self(*args) 

466 

467 if len(args) < 1: 

468 raise TypeError('partial type takes at least one argument') 

469 

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

471 

472 if not callable(wrapped): 

473 raise TypeError('the first argument must be callable') 

474 

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

476 

477 self._self_args = args 

478 self._self_kwargs = kwargs 

479 

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

481 def _unpack_self(self, *args): 

482 return self, args 

483 

484 self, args = _unpack_self(*args) 

485 

486 _args = self._self_args + args 

487 

488 _kwargs = dict(self._self_kwargs) 

489 _kwargs.update(kwargs) 

490 

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

492 

493class _FunctionWrapperBase(ObjectProxy): 

494 

495 __slots__ = ('_self_instance', '_self_wrapper', '_self_enabled', 

496 '_self_binding', '_self_parent', '_self_owner') 

497 

498 def __init__(self, wrapped, instance, wrapper, enabled=None, 

499 binding='callable', parent=None, owner=None): 

500 

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

502 

503 object.__setattr__(self, '_self_instance', instance) 

504 object.__setattr__(self, '_self_wrapper', wrapper) 

505 object.__setattr__(self, '_self_enabled', enabled) 

506 object.__setattr__(self, '_self_binding', binding) 

507 object.__setattr__(self, '_self_parent', parent) 

508 object.__setattr__(self, '_self_owner', owner) 

509 

510 def __get__(self, instance, owner): 

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

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

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

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

515 # here in this base class. 

516 # 

517 # The distinguishing attribute which determines whether we are being 

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

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

520 # 

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

522 # case we perform the binding. 

523 # 

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

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

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

527 # 

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

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

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

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

532 

533 if self._self_parent is None: 

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

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

536 

537 if self._self_binding == 'builtin': 

538 return self 

539 

540 if self._self_binding == "class": 

541 return self 

542 

543 binder = getattr(self.__wrapped__, '__get__', None) 

544 

545 if binder is None: 

546 return self 

547 

548 descriptor = binder(instance, owner) 

549 

550 return self.__bound_function_wrapper__(descriptor, instance, 

551 self._self_wrapper, self._self_enabled, 

552 self._self_binding, self, owner) 

553 

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

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

556 # ourselves again. This mirrors what Python does. 

557 # 

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

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

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

561 

562 if self._self_instance is None and self._self_binding in ('function', 'instancemethod', 'callable'): 

563 descriptor = self._self_parent.__wrapped__.__get__( 

564 instance, owner) 

565 

566 return self._self_parent.__bound_function_wrapper__( 

567 descriptor, instance, self._self_wrapper, 

568 self._self_enabled, self._self_binding, 

569 self._self_parent, owner) 

570 

571 return self 

572 

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

574 def _unpack_self(self, *args): 

575 return self, args 

576 

577 self, args = _unpack_self(*args) 

578 

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

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

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

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

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

584 

585 if self._self_enabled is not None: 

586 if callable(self._self_enabled): 

587 if not self._self_enabled(): 

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

589 elif not self._self_enabled: 

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

591 

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

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

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

595 

596 if self._self_binding in ('function', 'instancemethod', 'classmethod', 'callable'): 

597 if self._self_instance is None: 

598 instance = getattr(self.__wrapped__, '__self__', None) 

599 if instance is not None: 

600 return self._self_wrapper(self.__wrapped__, instance, 

601 args, kwargs) 

602 

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

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

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

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

607 # wrapped using the staticmethod decorator. 

608 

609 return self._self_wrapper(self.__wrapped__, self._self_instance, 

610 args, kwargs) 

611 

612 def __set_name__(self, owner, name): 

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

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

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

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

617 # FunctionWrapper used by decorators. 

618 

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

620 self.__wrapped__.__set_name__(owner, name) 

621 

622 def __instancecheck__(self, instance): 

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

624 # instance of the `__wrapped__`. 

625 return isinstance(instance, self.__wrapped__) 

626 

627 def __subclasscheck__(self, subclass): 

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

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

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

631 # broader implications of doing that. Thus restrict to 

632 # FunctionWrapper used by decorators. 

633 

634 if hasattr(subclass, "__wrapped__"): 

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

636 else: 

637 return issubclass(subclass, self.__wrapped__) 

638 

639class BoundFunctionWrapper(_FunctionWrapperBase): 

640 

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

642 def _unpack_self(self, *args): 

643 return self, args 

644 

645 self, args = _unpack_self(*args) 

646 

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

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

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

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

651 # evaluate it as a boolean. 

652 

653 if self._self_enabled is not None: 

654 if callable(self._self_enabled): 

655 if not self._self_enabled(): 

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

657 elif not self._self_enabled: 

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

659 

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

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

662 

663 if self._self_binding == 'function': 

664 if self._self_instance is None and args: 

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

666 if isinstance(instance, self._self_owner): 

667 wrapped = PartialCallableObjectProxy(self.__wrapped__, instance) 

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

669 

670 return self._self_wrapper(self.__wrapped__, self._self_instance, 

671 args, kwargs) 

672 

673 elif self._self_binding == 'callable': 

674 if self._self_instance is None: 

675 # This situation can occur where someone is calling the 

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

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

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

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

680 # see anything as being different. 

681 

682 if not args: 

683 raise TypeError('missing 1 required positional argument') 

684 

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

686 wrapped = PartialCallableObjectProxy(self.__wrapped__, instance) 

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

688 

689 return self._self_wrapper(self.__wrapped__, self._self_instance, 

690 args, kwargs) 

691 

692 else: 

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

694 # staticmethod, then _self_instance will only tell us whether 

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

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

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

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

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

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

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

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

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

704 # decoratored function. 

705 

706 instance = getattr(self.__wrapped__, '__self__', None) 

707 

708 return self._self_wrapper(self.__wrapped__, instance, args, 

709 kwargs) 

710 

711class FunctionWrapper(_FunctionWrapperBase): 

712 

713 __bound_function_wrapper__ = BoundFunctionWrapper 

714 

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

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

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

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

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

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

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

722 # method of knowing. 

723 # 

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

725 # 

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

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

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

729 # wrapper objects. 

730 # 

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

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

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

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

735 # distinguish it from wrapping a normal function outside of 

736 # a class context. 

737 # 

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

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

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

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

742 # 

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

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

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

746 # binding will have been performed where the instance against 

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

748 # 

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

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

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

752 # unnbound method no longer exists. 

753 # 

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

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

756 # have been perfomed where the instance was not None. 

757 # 

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

759 # method was a static method. 

760 # 

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

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

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

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

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

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

767 # thing where classmethod and staticmethod are used. 

768 # 

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

770 # decorators around classmethod and staticmethod, likelihood of 

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

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

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

774 # 

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

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

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

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

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

780 # 

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

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

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

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

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

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

787 

788 binding = None 

789 

790 if isinstance(wrapped, _FunctionWrapperBase): 

791 binding = wrapped._self_binding 

792 

793 if not binding: 

794 if inspect.isbuiltin(wrapped): 

795 binding = 'builtin' 

796 

797 elif inspect.isfunction(wrapped): 

798 binding = 'function' 

799 

800 elif inspect.isclass(wrapped): 

801 binding = 'class' 

802 

803 elif isinstance(wrapped, classmethod): 

804 binding = 'classmethod' 

805 

806 elif isinstance(wrapped, staticmethod): 

807 binding = 'staticmethod' 

808 

809 elif hasattr(wrapped, '__self__'): 

810 if inspect.isclass(wrapped.__self__): 

811 binding = 'classmethod' 

812 elif inspect.ismethod(wrapped): 

813 binding = 'instancemethod' 

814 else: 

815 binding = 'callable' 

816 

817 else: 

818 binding = 'callable' 

819 

820 super(FunctionWrapper, self).__init__(wrapped, None, wrapper, 

821 enabled, binding)