Lets say I have the following 2 classes in module a
class Real(object):
...
def print_stuff(self):
print 'real'
class Fake(Real):
def print_stff(self):
print 'fake'
in module b
it uses the Real
class
from a import Real
Real().print_stuff()
How do I monkey patch so that when b
imports Real
it's actually swapped with Fake
?
I was trying to do like this in initialize script but it doesn't work.
if env == 'dev':
from a import Real, Fake
Real = Fake
My purpose is to use the Fake class in development mode.
You can use patch
from the mock
module. Here is an example:
with patch('yourpackage.b.Real') as fake_real:
fake_real.return_value = Fake()
foo = b.someClass()
foo.somemethod()
The issue is that when you do -
from a import Real, Fake
You are basically importing those two classes into your initialize
script's namespace and creating Real
and Fake
names in the initialize
script's namespace. Then you make the name Real
in initialize
script point to Fake
, but that does not change anything in the actual a
module.
If initialize
script is another .py
module/script at runs at the start of your original program , then you can use the below -
if env == 'dev':
import a
a.Real = a.Fake
Please note, this would make a.Real
to refer to the Fake
class whenever you use Real
from a
module after the above line is executed.
Though I would suggest that a better way would be to do this in your a
module itself, by making it possible to check the env
in that module, as -
if <someothermodule>.env == 'dev':
Real = Fake
As was asked in the comments -
Doesn't import a also import into initialize script's namespace? What's the difference between importing modules and classes?
The thing is that when you import just the class using from a import class
, what you actually do is create that variable, class
in your module namespace (in the module that you import it to) , changing that variable to point to something new in that module namespace does not affect the original class in its original module-object, its only affected in the module in which its changed.
But when you do import a
, you are just importing the module a
(and while importing the module object also gets cached in the sys.modules
dictionary, so any other imports to a
from any other modules would get this cached version from sys.modules
) (Another note, is that from a import something
also internally imports a
and caches it in sys.modules
, but lets not get into those details as I think that is not necessary here).
And then when you do a.Real = <something>
, you are changing the Real
attribute of a
module object, which points to the class, to something else, this mutates the a
module directly, hence the change is also reflected, when the module a
gets imported from some other module.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With