3

My question is similar to this question

Except that it's not my module to execute dosomething() in thirdpartymodule_b so I need to monkey patch thirdpartymodule_a and be effective when it's executed in thirdpartymodule_b

Community
  • 1
  • 1
James Lin
  • 25,028
  • 36
  • 133
  • 233
  • 1
    I would love for someone to tell me how this is possible if `thirdpartymodule_b` is already importing `thirdpartymodule_a`. I have never been able to do this. – 2rs2ts Feb 21 '14 at 02:19
  • You want to monkey-patch `thirdpartymodule_a` so that only `thirdpartymodule_b` uses the patched version, while other modules would still use the old one? – warvariuc Feb 21 '14 at 02:19
  • @warwaruk that's correct, reason for that is I want to patch a form in a thirdparty app in django, which is used by it's view. – James Lin Feb 21 '14 at 02:24
  • I don't really understand. If you "patch a form in a thirdparty app in django, which is used by it's view" don't you expect that the other modules should also use the patched version? – warvariuc Feb 21 '14 at 02:41
  • @warwaruk yes I want the same module should also use the patch version, I think your answer guessed it, maybe the urls.py imports the class views which imports the form before my patch. – James Lin Feb 21 '14 at 03:38

1 Answers1

3

I don't see any difference between the question you referenced and your situation. In both cases a modules import a name from another module and you want to patch the object referenced by that name.

In that question the module is written by the author, in your question it's a third party module.

I think your problem lies in the fact the the third party already imported the object name, so if you try to replace the object in the module where it resides, the third party module will still use the old one, because it still references the old object.

module_1.py

class AForm(Form):
    ...

module_2.py

from module_1 import AForm

If you import module_2 and then monkey-patch module_1 replace AForm with another object

class AFormPatched(Form):
    ...

import module_1
module_1.AForm = AFormPatched

Your changes will not affect module_2, because module_2.AForm still points to the original object.

To solve this:

Option 1. module_2 should look like:

import module_1
module_1.AForm  # using AForm in this form

Option 2. Patch also module_2.AForm:

class AFormPatched(Form):
    ...

import module_1
module_1.AForm = AFormPatched
import module_2
module_2.AForm = AFormPatched

Or don't patch module_1 you want only module_2 to use the patched version.

Option 3. Patch attributes of the object. If you don't want to or cannot monkey patch all the places where the object name is used, sometimes it works if you don't replace the object, but patch only some of its attributes. It depends on the object and the behavior you are trying to patch:

import third_party_module
third_party_module.AForm.__init__ = ...
warvariuc
  • 57,116
  • 41
  • 173
  • 227