tags:

views:

104

answers:

4

I have cyclical import issues adding some new code to a very large app, and I'm trying to determine which files are the most likely causes for this. It there any way to track which files import which files? I did a bit of looking and found the python trace command, but it's just showing a bunch of activity in the main python libraries.

I'm basically looking for an app that will show me something like:

App1 >>imports>> App2,App3.method
App2 >>imports>> App3,etc

I could just look through all of my files, but I'd rather not, it's a big app.

+1  A: 

It shouldn't be possible to get a cyclic import in python because it checks if the module has already been imported before importing it again. You can only import a module once, no matter how many times you call import.

From http://groups.google.com/group/comp.lang.python/browse%5Fthread/thread/1d80a1c6db2b867c?pli=1 :

Imports are pretty straightforward really. Just remember the following:

'import' and 'from xxx import yyy' are executable statements. They execute when the running program reaches that line.

If a module is not in sys.modules, then an import creates the new module entry in sys.modules and then executes the code in the module. It does not return control to the calling module until the execution has completed.

If a module does exist in sys.modules then an import simply returns that module whether or not it has completed executing. That is the reason why cyclic imports may return modules which appear to be partly empty.

Finally, the executing script runs in a module named __main__, importing the script under its own name will create a new module unrelated to __main__.

Take that lot together and you shouldn't get any surprises when importing modules.

Mark Byers
It is very possible to get cyclic imports. They won't loop infinitely, but they can create problems where a function isn't defined when needed because two files import each other.
Ned Batchelder
+3  A: 

Try using python -v to run your program. It will trace the sequence of imports.

Another option is pylint, which will alert you to all sorts of issues, including cyclic imports.

Ned Batchelder
+2  A: 

You could use one of these scripts to make python module dependency graphs:

unutbu
Snakefood ended up being what I wanted. It takes some massaging to make it work for a larger number of files though.
Jeff
@Jeff: Yes, it does take a little work to setup and reading the documentation is a must. I'm glad you were able to get it to work!
unutbu
+6  A: 

Here's a simple (and slightly rudimentary;-) way to trace "who's trying to import what" in terms of module names:

import inspect
import __builtin__
savimp = __builtin__.__import__

def newimp(name, *x):
  caller = inspect.currentframe().f_back
  print name, caller.f_globals.get('__name__')
  return savimp(name, *x)

__builtin__.__import__ = newimp

which gives, for example (having saved this as tracimp.py):

$ python -c 'import tracimp; import email; import sys; import email.mime'
email __main__
sys email
email.mime email
sys __main__
email.mime __main__

As you see, one specific characteristic of "wrapping" the __import__ built-in is that it won't be silenced by the fact that a module being imported is already in sys.modules: since taking care of that is one of __import__'s jobs, our wrapper gets called for both modules "being loaded for the first time" and ones that are just going to get fetched from sys.modules because they were already imported previously. This should come in really handy when you're trying to diagnose circular imports (it boils down to finding loops in the directed graph whose edges are identified by the two module names -- imported and importer -- which this simple approach is printing on each output line).

Alex Martelli