How can I log all imports that are executed in a block of code?
<p>I'm writing a test suite, and the code I'm testing makes excessive use of delayed module imports.  So it's possible that with 5 different inputs to the same method, this may end up importing 5 additional modules.  What I'd like to be able to do is set up tests so that I can assert that running the method with one input causes one import, and doesn't cause the other 4.</p>

<p>I had a few ideas of how to start on this, but none so far have been successful.  I already have a custom importer, and I can put the logging code in the importer.  But this doesn't work, because the import statements only run once.  I need the log statement to be executed regardless of if the module has been previously imported.  Just running <code>del sys.modules['modname']</code> also doesn't work, because that runs in the test code, and I can't reload the module in the code being tested.</p>

<p>The next thing I tried was subclassing <code>dict</code> to do the monitoring, and replace sys.modules with this subclass.  This subclass has a reimplemented <code>__getitem__</code> method, but calling <code>import module</code> doesn't seem to trigger the <code>__getitem__</code> call in the subclass.  I also can't assign directly to <code>sys.modules.__getitem__</code>, because it is read-only.</p>

<p>Is what I'm trying to do even possible?</p>

<p><strong>UPDATE</strong></p>

<p>nneonneo's answer seems to only work if the implementation of <code>logImports()</code> is in the same module as where it is used.  If I make a base test class containing this functionality, it has problems.  The first is that it can't find just <code>__import__</code>, erroring with:</p>

<pre><code>#     old_import = __import__
# UnboundLocalError: local variable '__import__' referenced before assignment
</code></pre>

<p>When I change that to <code>__builtin__.__import__</code>, I another error:</p>

<p>myunittest.py:</p>

<pre><code>import unittest
class TestCase(unittest.TestCase):
    def logImports(self):
        old_import = __builtins__.__import__
        def __import__(*args, **kwargs):
            print args, kwargs
            return old_import(*args, **kwargs)

        __builtins__.__import__ = __import__
</code></pre>

<p>test.py:</p>

<pre><code>import myunittest
import unittest
class RealTest(myunittest.TestCase):
    def setUp(self):
        self.logImports()
    def testSomething(self):
        import unittest
        self.assertTrue(True)
unittest.main()

#     old_import = __builtins__.__import__
# AttributeError: 'dict' object has no attribute '__import__'
</code></pre>
