views:

42

answers:

3

I have a series of python modules written which are held in the same directory and I am having trouble with an ImportError.

The three modules I am using are draw_menu.py, errors.py and file_operations.py.

In errors.py I requires a list of error codes, I am using a custom method defined in file_operations.py to open a file containing the codes therefore I am using import file_operations just below the she-bang (above the class definition).

In file_operations.py I use a method defined in error.py to print error messages upon errors (e.g. file not found etc.). I therefore import errors in the same way here.

The above has been working fine but when I come to using draw_menu.py which uses a file to define the options in an ascii menu (therefore I am using import file_operations) an ImportError is encountered.

ImportError: cannot import name file_operations

I understand that this is because the 'import tree' if you like flows as follows:

draw_menu <- file_operations <- errors <- file_operations

It is important that each module can be used individually, why is this an issue and how can I overcome this without removing import file_operations from errors.py?

Thankyou

Tom

+2  A: 

Circular imports can cause issues in Python (as you might expect). It's probably worth checking if:

A) errors.py and file_operation.py should be single module (if they both rely so heavily on each other, do they need to be separate?)

B) you can delay the import in one or the other module. An import statement in a function will not run until the function is called, and while it's normally good practice to import at the beginning of a module there is no requirement to in Python. In situations like this it can avoid the circular reference during import.

mavnn
Thank you for your fast response, I have kept the two modules seperate and moved the `import file_operations` within the required methods defined within `errors.py` and this has solved my issue. What kind of issues typically arise from a circular import?
Thorsley
@Thorsley: http://stackoverflow.com/questions/3082015/python-module-initialization-order/3082097#3082097
Ignacio Vazquez-Abrams
There's an old but very good article on importing in python at http://effbot.org/zone/import-confusion.htm with a section on circular imports. Well worth reading.
mavnn
Thanks, I'll check it out
Thorsley
+1  A: 

The problem is not the imports themselves, but the dependencies. file_operations cannot be processed until it has imported errors, but errors cannot be processed until it has imported file_operations. Python recognises this as an impossible situation, and raises an error.

The best solution to this is to refactor your files so that you don't have this circular dependency any more. If this really isn't possible, the alternative solution is to change one of the modules so that the offending import happens inside the function that needs it, rather than at the top level. This means the initial processing of the module isn't dependent on the import, so it will succeed.

Daniel Roseman
This is incorrect. References in the other module cannot be *used* until the import process has completed far enough for them to be defined, but simply *importing* the module is not a problem.
Ignacio Vazquez-Abrams
A: 

Apart from breaking the circular dependency you can try moving the locations of your import calls. Don't forget that imports in Python are just regular statements, so you can import inside functions for example.

The trouble is that import (as a side-effect) will actually run the module being imported (the first time you call import). So if you are importing a module, which imports the original module things get confused.

You may find that you can ease the problem by only importing errors/file_operations at the point you actually need to use it. This could be inside a function. So maybe wrap the call to the function in errors:


def print_error_message(err):
    from errors import print_error_message as _print_error_message
    _print_error_message(err)

That way you will only import errors after the regular imports have run.

John Montgomery
Or you could just `import errors` at the top and use `errors.print_error_message` inside the function.
Ignacio Vazquez-Abrams