Python Circular Import Problem and Solutions

We love to use modules in Python and why not, they provide additional functionalities, better coding practice, and always create a proper structure while using. But many times unknowingly, we can run into python circular import problems if we accidentally have another file named as module’s name. As python prefers importing from the local current directory first and then from site-packages, it will create a circular import problem.

Generally, the Python Circular Import problem occurs when you accidentally name your working file the same as the module name and those modules depend on each other. This way the python opens the same file which causes a circular loop and eventually throws an error.

For example, when you name your file as random.py and try to import “from random import randint”, it’ll throw a circular import error (also termed as from partially initialized module).

In this post, we’ll have a look at all the causes and their solutions for circular import.

How Circular Import Is Identified?

Python Circular Import Flowchart

Then a module calls an object within itself, circular import error is raised. Let’s consider an example where you are working on a ‘rea.py’ python file and you write a code as ‘from rea import x’. This will cause python to import the object x from the rea module.

This will cause a circular call within the code and it’ll throw an exception with an error mentioned as “ImportError: cannot import name ‘x’ from partially initialized module ‘rea’ (most likely due to a circular import) (/home/pythonpool/rea.py)”.

This exception is raised when you try to import any type of object. There are no exceptions.

Tip: Circular import is only raised when you import object from module. It is not raised when you try to import module itself. So, in above example, “import rea” will work just fine.

How to fix Python Circular Import?

There are several workarounds to solve the circular import problem. Each of these workarounds has its different use cases. Make sure you use the solution that suits best for your problem.

Conditional Import is also one of the ways by which you can handle such cases but does not try to use try-except blocks to fix circular imports as the core problem of importing variables still remain even if we ignore it.

Importing The Module Itself

There is a good workaround Python circular import error that you can import the module itself rather than importing object/function from the module. This way you can import and use all the objects and variables from the module.

Suppose, a module named module_name has function func_name, and you want to import it but it throws a circular error.

The easiest way to make this work is by importing the module_name itself. The following example will help you to understand it –

rea.py –

import rea

x=1

if __name__ == '__main__':
    print(rea.x)

Even if you are calling the same module, it’ll work. Use these cases to fix the issues in flask and Django where the filenames can match the pre-defined module names.

Rename Your Working file

Sometimes, we can name our working file to module name without knowing its consequences (Even I did it many times :P). Renaming the file will work perfectly in such cases. For example, if you want to use the numpy module, you should avoid your working file naming numpy.py.

Here’s an example –

– numpy.py –

from numpy import array

x = array([1, 2, 3])
ImportError: cannot import name 'array' from partially initialized module 'numpy' (most likely due to a circular import) (/home/pythonpool/numpy.py)

Now, rename our working file to a different name –

– pool_numpy.py –

from numpy import array

x = array([1, 2, 3])
print(x)
[1 2 3]

Just as we avoid naming variables to built-in variables to avoid issues, you need to avoid naming your file to module name to avoid conflicts.

Avoid Circular Import Calls

Consider the following example –

– module1.py –

from module2 import func2

def func1():
	func2()

– module2.py –

from module1 import func1

def func2():
	func1()

Command to run –

python .\module1.py
Traceback (most recent call last):
  File "/home/pythonpool/module1.py", line 1, in <module>
    from module2 import func2
  File "/home/pythonpool/module2.py", line 1, in <module>
    from module1 import func1
  File "/home/pythonpool/module1.py", line 1, in <module>
    from module2 import func2
ImportError: cannot import name 'func2' from partially initialized module 'module2' (most likely due to a circular import) (/home/pythonpool/module2.py)

The above example demonstrates a situation where you try to import a variable from module2 which is partially initialized (python doesn’t know that func2 even exists or not).

In such cases try to copy the required function/object to your working file.

In the above example, if you declare func2 itself in module1, it’ll not be of any problem.

Solve Circular Import Error In Django

Ever tried importing Django modules/classes in your Django project? You’ll definitely encounter a python circular import error once in such scenarios. If you try to implement the Django model manually by directly importing it, it’ll throw an error.

For example, you have your Django installed apps as follows –


INSTALLED_APPS = (
    'app1',
)

And you want to use the structure of app1, you might import it directly in your python file considering its installed app. Something like this –

from app1.models import App1

Then most likely, you’ll encounter the python circular import error in your code. This is the incorrect way of importing a Model in your Django Application. Following is the correct way to do it –

For Django <=1.7:

from django.db.models import get_model
MyModel = get_model('app1',  'App1')

For Django > 1.7:

from django.apps import apps
apps.get_model('app1.App1')

This way the model ‘App1’ from app ‘app1’ will be imported into your Django application directly.

Solution for Python Circular Import Error In Flask

Similar to Django, flask also has circular import issues especially when you’re dealing with SQLAlchemy. If you try to use the database model of SQLAlchemy (declared in the main app file) in a different file, it’ll throw a circular import error.

Consider the following examples –

– app.py –

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__ name __)
db = SQLAlchemy(app)  
from models import routes

– routes.py –

from app import db

This is indeed a circular import as app.py called routes and routes call DB from app.py. To fix such issues we create a separate extension for a database where we initialize the SQLAlchemy database.

from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()

This can be imported in app.py and models.py and used accordingly.

FAQs

Is there any python circular import detector?

Pycycle is a Github project which aims to detect circular import problems in your code. This tool has good command-line usage with multiple arguments usage.

Importing Static Variable at class level cause circular import?

Yes, if there is another import statement calling working module again, then it may cause circular import.

What causes circular import problems in __init__.py file?

__init__ file is responsible for importing and initializing packages. During this process, we always tend to import other modules from the package. So, if your other module calls back to another module that is yet to initialize in __init__, it’ll throw a circular import.

References

Python Import System: How searching of Modules works in Python.


Subscribe
Notify of
guest
0 Comments
Inline Feedbacks
View all comments