Why does importing modules result in a circular import error

I have this for the layout of my project:

projectFolder /       setup/          __init__.py          setup.py       Utils /          __init__.py          cloudmanager.py startup.py 

I am trying to import the Setup Module inside my cloudmanager.py script (which is nested in one more directory). I can easily import both the setup module and the Utils module inside my startup.py script since it’s in the root directory.

I’ve tried (inside my cloudmanager.py script):

from . import setup 

Which gives me the error of:

ImportError: cannot import name 'setup' from partially initialized module 'Utils' (most likely due to a circular import) 

and I’ve tried:

from .. import setup 

Which gives me the error of:

ValueError: attempted relative import beyond top-level package 

Any help? There are questions like this out there but they steer towards to using OS, which I’d like to avoid…

Add Comment
2 Answer(s)

Try to use:

import setup.setup 
Add Comment

Okay, so the reason you’re getting an error importing .. setup is indeed that you can’t do relative imports when the parent directory is a package. A package is any directory with a __init__.py file in it.

You could solve this by doing one of two things:

  1. You could make sure the root of your project is in the Python path and import everything in the root.
  2. You could make your project’s root directory itself a package and then use relative imports.

Option 1: Importing from the project root

If your projectFolder folder lives at /home/you/projects/projectFolder, make sure your PYTHONPATH has /home/you/projects/projectFolder in it. For example, when you run your main script, you could set it before hand. In bash (assuming a Unix environment):

export PYTHONPATH=/home/you/projects/projectFolder python /home/you/projects/projectFolder/startup.py 

You could also do that inside startup.py, if you want to avoid changing the external environment:

# startup.py  import os, sys sys.path.append(os.path.join(os.path.dirname(__file__))) 

If you do that in startup.py, the directory of startup.py will always be in the Python path.

Once you one of those, you can base all your imports on the relative location of your project. Eg:

import setup.setup import Utils.cloudmanager 

(That will work in every file you import after the sys.path mutation runs)

Option 2: Relative imports

If you make your project’s root a Python package, you can use relative imports entirely. Eg, you’d have these files:

projectFolder/__init__.py projectFOlder/setup/__init__.py projectFolder/setup/setup.py projectFolder/Utils/__init__.py projectFolder/Utils/cloudmanager.py 

If you do that, inside cloudmanager.py, you could run from .. import setup just fine.

What do you do?

Both of these are valid options. In general relative imports have less ambiguity, since they avoid name collisions, but they’re a newer feature of Python so option #1 is more common, in general.

Add Comment

Your Answer

By posting your answer, you agree to the privacy policy and terms of service.