简体   繁体   中英

Temporarily removing a python module

I'm trying to temporarily remove a python module from sys.modules so that I can import it as part of a test case (with various system functions mocked out) and then put it back again. (Yes, that's a bit crazy and I'm probably going to end up restructuring the code instead but now I'm curious...)

I can remove the module and reimport it just fine but I can't seem to put it back to the original module once I'm finished. (Maybe that's just not posible?) Here's a test case that I wrote to test out the idea:

class Test(unittest.TestCase):

    def test_assumptions(self):
        import meta.common.fileutils as fu1
        del(sys.modules["meta.common.fileutils"])
        import meta.common.fileutils
        del(sys.modules["meta.common.fileutils"])
        sys.modules["meta.common.fileutils"] = fu1 # I hoped this would set the module back
        import meta.common.fileutils as fu2
        self.assertEqual(fu1, fu2)  # assert fails, fu2 is a new copy of module :-(

Can anyone suggest why it might be failing?

Edit, using pop() as suggested by one of the answers also fails:

class Test(unittest.TestCase):

    def test_assumptions(self):
        import meta.common.fileutils as fu1
        orig = sys.modules.pop("meta.common.fileutils")
        import meta.common.fileutils
        del(sys.modules["meta.common.fileutils"])
        sys.modules["meta.common.fileutils"] = orig 
        import meta.common.fileutils as fu2
        self.assertEqual(fu1, orig) # passes
        self.assertEqual(fu2, orig) # fails
        self.assertEqual(fu1, fu2)  # fails

The sys.modules structure is really just a Python dict . You can remove modules from it, and you can also put them back in .

Store the original module object in a local variable, using dict.pop() to both remove the module and return it:

orig = sys.modules.pop('meta.common.fileutils')

then, when it comes to restoring it, just put that object back into sys.modules :

sys.modules['meta.common.fileutils'] = orig

It looks to me like the issue here has to do with packages. In particular, for a module that lives in a package (eg meta.common ), there are two ways to access it: via sys.modules , and via the parent package's dictionary (ie, meta.common.__dict__ ). It looks to me like the import meta.common.fileutils as fu2 line is getting fu2 's value from meta.common.__dict__ , and not from sys.modules .

So the solution: in addition to monkey-patching sys.modules, you should also monkey-patch the parent package. Ie, add something like this:

>>> import meta.common
>>> meta.common.fileutils = fu1

right before the sys.modules["meta.common.fileutils"] = fu1 line.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM