wire.py 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  1. """:mod:`wirerope.wire` --- end-point instant for each bound method
  2. ===================================================================
  3. """
  4. import six
  5. import types
  6. from .callable import Descriptor
  7. from ._compat import functools
  8. __all__ = 'Wire',
  9. @functools.singledispatch
  10. def descriptor_bind(descriptor, obj, type_):
  11. binder = Descriptor(descriptor).detect_binder(obj, type_)
  12. return binder(descriptor, obj, type_)
  13. @descriptor_bind.register(types.FunctionType)
  14. def descriptor_bind_function(descriptor, obj, type):
  15. return obj, obj
  16. class Wire(object):
  17. """The core data object for each function for bound method.
  18. Inherit this class to implement your own Wire classes.
  19. - For normal functions, each function is directly wrapped by **Wire**.
  20. - For any methods or descriptors (including classmethod, staticmethod),
  21. each one is wrapped by :class:`wirerope.rope.MethodRopeMixin`
  22. and it creates **Wire** object for each bound object.
  23. """
  24. __slots__ = (
  25. '_rope', '_callable', '_binding', '__func__', '_owner',
  26. '_bound_objects')
  27. def __init__(self, rope, owner, binding):
  28. self._rope = rope
  29. self._callable = rope.callable
  30. self._owner = owner
  31. self._binding = binding
  32. if binding:
  33. func = self._callable.wrapped_object.__get__
  34. if self._callable.is_property:
  35. wrapped = functools.partial(func, *binding)
  36. if six.PY2:
  37. # functools.wraps requires those attributes but
  38. # py2 functools.partial doesn't have them
  39. wrapped.__module__ = owner.__module__
  40. wrapped.__name__ = func.__name__
  41. self.__func__ = wrapped
  42. else:
  43. self.__func__ = func(*binding)
  44. else:
  45. self.__func__ = self._callable.wrapped_object
  46. if self._binding is None:
  47. self._bound_objects = ()
  48. else:
  49. _, binder = descriptor_bind(
  50. self._callable.wrapped_object, *self._binding)
  51. if binder is not None:
  52. self._bound_objects = (binder, )
  53. else:
  54. self._bound_objects = ()
  55. assert callable(self.__func__), self.__func__
  56. if rope._wrapped:
  57. functools.wraps(self.__func__)(self)
  58. def _on_property(self):
  59. return self.__func__()