55
66import types
77
8+ from python_toolbox import misc_tools
89from python_toolbox import decorator_tools
910from python_toolbox import caching
1011
1112
1213@decorator_tools .helpful_decorator_builder
13- def monkeypatch_method (class_ , name = None ):
14+ def monkeypatch_method (monkeypatchee , name = None ):
1415 '''
16+ blocktododoc
1517 Monkeypatch a method into a class.
1618
1719 Example:
@@ -32,28 +34,44 @@ def my_method(a):
3234
3335 You can also use this to monkeypatch a `CachedProperty` into a class.
3436 '''
37+
38+ monkeypatchee_is_a_class = misc_tools .is_type (monkeypatchee )
39+ class_of_monkeypatchee = monkeypatchee if monkeypatchee_is_a_class else \
40+ misc_tools .get_actual_type (monkeypatchee )
41+
3542 def decorator (function ):
3643 # Note that unlike most decorators, this decorator retuns the function
3744 # it was given without modifying it. It modifies the class only.
3845 if isinstance (function , types .FunctionType ):
3946 name_ = name or function .__name__
40- new_method = types .MethodType (function , None , class_ )
47+
48+ new_method = types .MethodType (function , None , monkeypatchee ) if \
49+ monkeypatchee_is_a_class else types .MethodType (function ,
50+ monkeypatchee , class_of_monkeypatchee )
4151 # todo: Last line was: `new_method = types.MethodType(function,
4252 # class_)`, is subtly wrong, make tests to prove
43- setattr (class_ , name_ , new_method )
44- return function
45- elif isinstance (function , caching .CachedProperty ):
46- cached_property = function
47- if not isinstance (cached_property .getter , types .FunctionType ):
48- raise NotImplemented
49- name_ = cached_property .getter .__name__
50- setattr (class_ , name_ , cached_property )
51- return cached_property
52- elif isinstance (function , (classmethod , staticmethod )):
53- name_ = function .__func__ .__name__
54- setattr (class_ , name_ , function )
53+ setattr (monkeypatchee , name_ , new_method )
5554 return function
5655 else :
57- raise NotImplemented ("`monkeypatch_method` doesn't know how to "
58- "handle this kind of function." )
59- return decorator
56+ # `function` is probably some kind of descriptor.
57+ if not monkeypatchee_is_a_class :
58+ raise NotImplemented ("I don't know how to monkeypatch a "
59+ "descriptor onto a non-class object." )
60+ ### Getting name of descriptor: ###################################
61+ # #
62+ if isinstance (function , caching .CachedProperty ):
63+ if not isinstance (function .getter , types .FunctionType ):
64+ raise NotImplemented
65+ name_ = function .getter .__name__
66+ elif isinstance (function , (classmethod , staticmethod )):
67+ name_ = function .__func__ .__name__
68+ else :
69+ raise NotImplemented ("`monkeypatch_method` doesn't know how "
70+ "to handle this kind of function." )
71+ # #
72+ ### Finished getting name of descriptor. ##########################
73+ setattr (monkeypatchee , name_ , function )
74+ return function
75+
76+ return decorator
77+
0 commit comments